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

Go to the documentation of this file.
00001 /*!***************************************************************************
00002 *! FILE NAME  : circbuf.c
00003 *! DESCRIPTION: drivers to manipulate large circular buffer thet holds compressed
00004 *! images/video. Buffer frame data is filled in by the FPGA, frame pointers and
00005 *! essential frames metadata filled during servicing of the interruptsl
00006 *! This code is based on the code from cxdma.c
00007 *! TODO: Add buffer reset, JPEG header generation here
00008 *!
00009 *! Copyright (C) 2002-2007 Elphel, Inc
00010 *! -----------------------------------------------------------------------------**
00011 *!
00012 *!  This program is free software: you can redistribute it and/or modify
00013 *!  it under the terms of the GNU General Public License as published by
00014 *!  the Free Software Foundation, either version 3 of the License, or
00015 *!  (at your option) any later version.
00016 *!
00017 *!  This program is distributed in the hope that it will be useful,
00018 *!  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 *!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 *!  GNU General Public License for more details.
00021 *!
00022 *!  You should have received a copy of the GNU General Public License
00023 *!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00024 *! -----------------------------------------------------------------------------**
00025 *!  $Log: circbuf.c,v $
00026 *!  Revision 1.1.1.1  2008/11/27 20:04:00  elphel
00027 *!
00028 *!
00029 *!  Revision 1.20  2008/11/20 07:06:24  elphel
00030 *!  started more poll options
00031 *!
00032 *!  Revision 1.19  2008/11/03 20:51:49  elphel
00033 *!  minor bug fix
00034 *!
00035 *!  Revision 1.18  2008/10/29 04:18:28  elphel
00036 *!  v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
00037 *!
00038 *!  Revision 1.17  2008/10/25 19:59:48  elphel
00039 *!  added lseek() calls to enable/disable daemons at events (compressed frame available, any frame available, histogram-Y and histograms-C available)
00040 *!
00041 *!  Revision 1.16  2008/10/23 08:01:30  elphel
00042 *!  comments
00043 *!
00044 *!  Revision 1.15  2008/10/19 06:50:03  elphel
00045 *!  removed couple # if 0
00046 *!
00047 *!  Revision 1.14  2008/10/13 16:55:53  elphel
00048 *!  removed (some) obsolete P_* parameters, renamed CIRCLSEEK to LSEEK_CIRC constants (same as other similar)
00049 *!
00050 *!  Revision 1.13  2008/10/12 16:46:22  elphel
00051 *!  snapshot
00052 *!
00053 *!  Revision 1.12  2008/10/06 08:31:08  elphel
00054 *!  snapshot, first images
00055 *!
00056 *!  Revision 1.11  2008/09/22 22:55:47  elphel
00057 *!  snapshot
00058 *!
00059 *!  Revision 1.10  2008/09/20 00:29:49  elphel
00060 *!  moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
00061 *!
00062 *!  Revision 1.9  2008/09/12 20:40:11  elphel
00063 *!  snapshot
00064 *!
00065 *!  Revision 1.8  2008/09/12 00:23:58  elphel
00066 *!  removed cc353.c, cc353.h
00067 *!
00068 *!  Revision 1.7  2008/09/11 01:05:29  elphel
00069 *!  snapshot
00070 *!
00071 *!  Revision 1.6  2008/09/07 19:48:08  elphel
00072 *!  snapshot
00073 *!
00074 *!  Revision 1.5  2008/09/05 23:20:26  elphel
00075 *!  just a snapshot
00076 *!
00077 *!  Revision 1.4  2008/05/26 23:32:59  elphel
00078 *!  Added driver to handle multi-frame parameters
00079 *!
00080 *!  Revision 1.3  2008/05/24 05:31:02  elphel
00081 *!  removed seek to current hardware write pointer after opening file, so now ftp-ing circbuf file works correctly
00082 *!
00083 *!  Revision 1.2  2008/05/16 06:06:27  elphel
00084 *!  adjusting drivers to the fpga code (03533020)
00085 *!
00086 *!  Revision 1.10  2008/04/11 23:16:51  elphel
00087 *!  removed unneeded local_irq_disable() after local_irq_save_flags()
00088 *!
00089 *!  Revision 1.8  2007/12/03 08:28:46  elphel
00090 *!  Multiple changes, mostly cleanup
00091 *!
00092 *!  Revision 1.7  2007/11/16 08:56:19  elphel
00093 *!  Added support for 2 additional commands to check circbuf usage
00094 *!
00095 *!  Revision 1.6  2007/11/05 06:08:25  elphel
00096 *!  fixed "first/second" bug introduced while fixing the previous one
00097 *!
00098 *!  Revision 1.5  2007/11/05 01:40:51  elphel
00099 *!  fixed wrong count of frames available, "second" frame
00100 *!
00101 *!  Revision 1.4  2007/11/04 05:46:06  elphel
00102 *!  removed debug, rearranged code to avoid a warning
00103 *!
00104 *!  Revision 1.3  2007/11/01 18:59:37  elphel
00105 *!  debugging mmap/caching problems
00106 *!
00107 *!  Revision 1.2  2007/10/27 00:55:32  elphel
00108 *!  untested revision - need to go
00109 *!
00110 *!  Revision 1.1.1.1  2007/10/02 23:54:58  elphel
00111 *!  This is a fresh tree based on elphel353-2.10
00112 *!
00113 *!  Revision 1.6  2007/10/02 23:54:58  elphel
00114 *!  LSEEK_CIRC_LAST will now return just write pointer, not an error if there are no frames yet available. Moving to previous will still generate error.
00115 *!
00116 *!  Revision 1.5  2007/10/02 22:29:38  elphel
00117 *!  made that only 0,SEEK_END can move beyond circbuf, fro SEEK_CUR and SEET_SET it will roll over to 0
00118 *!
00119 *!  Revision 1.4  2007/10/02 19:35:15  elphel
00120 *!  minor circbuf interface changes, bug fixes
00121 *!
00122 *!  Revision 1.3  2007/09/30 07:07:08  elphel
00123 *!  minor bug fix, disabled debug output
00124 *!
00125 *!  Revision 1.2  2007/09/30 03:19:56  elphel
00126 *!  Cleanup, fixed broken acquisition of individual JPEG images into circbuf (in mode 7)
00127 *!
00128 *!  Revision 1.1  2007/09/29 18:33:29  elphel
00129 *!  Split cxdma.c - /dev/circbuf is now in a separate circbuf.c file. New device driver does not support ioctl, so some curernt applications are updated to use other drivers to control the camera
00130 *!
00131 */
00132 
00133 /****************** INCLUDE FILES SECTION ***********************************/
00134 
00135 
00136 #include <linux/module.h>
00137 #include <linux/mm.h>
00138 #include <linux/sched.h>
00139 #include <linux/slab.h>
00140 #include <linux/errno.h>
00141 #include <linux/kernel.h>
00142 #include <linux/fs.h>
00143 #include <linux/string.h>
00144 #include <linux/init.h>
00145 #include <linux/autoconf.h>
00146 #include <linux/time.h>
00147 
00148 #include <asm/system.h>
00149 #include <asm/arch/memmap.h>
00150 //#include <asm/svinto.h> obsolete
00151 #include <asm/io.h>
00152 
00153 #include <asm/arch/dma.h>
00154 #include <asm/arch/hwregs/dma_defs.h>
00155 #include <asm/arch/hwregs/dma.h>
00156 #include <asm/arch/hwregs/reg_map.h>
00157 #include <asm/arch/hwregs/bif_dma_defs.h>
00158 
00159 
00160 #include <asm/irq.h>
00161 #include <asm/atomic.h>
00162 
00163 
00164 #include <asm/delay.h>
00165 #include <asm/uaccess.h>
00166 #include <asm/elphel/driver_numbers.h>
00167 #include <asm/elphel/c313a.h>
00168 
00169 #include "fpgactrl.h"  // defines port_csp0_addr, port_csp4_addr 
00170 #include "framepars.h" // just for ELPHEL_DEBUG bit mask
00171 
00172 #include "x3x3.h"
00173 //#include "cc3x3.h"
00174 #include "cxdma.h"
00175 #include "sensor_common.h"
00176 #include "jpeghead.h"
00177 #include "circbuf.h"
00178 #include "exif.h"
00179 #if ELPHEL_DEBUG
00180   #define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;}
00181 //  #define MDD1(x) printk("%s:%d:",__FILE__,__LINE__); x ; udelay (ELPHEL_DEBUG_DELAY)
00182   #define   D19(x) { if (GLOBALPARS(G_DEBUG) & (1 <<19)) {x; } ; }
00183   #define MDF19(x) { if (GLOBALPARS(G_DEBUG) & (1 <<19)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
00184   #define   D20(x) { if (GLOBALPARS(G_DEBUG) & (1 <<20)) {x; } ; }
00185   #define MDF20(x) { if (GLOBALPARS(G_DEBUG) & (1 <<20)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
00186 #else
00187   #define MDF(x)
00188 //  #define MDD1(x)
00189   #define   D19(x)
00190   #define MDF19(x)
00191   #define   D20(x)
00192   #define MDF20(x)
00193 
00194 #endif
00195 
00196 #define MD12(x)
00197 #define D(x)
00198 #define D1(x)
00199 //#define MD1(x) printk("%s:%d:",__FILE__,__LINE__);x
00200 #define MD1(x)
00201 //#define MD2(x) printk("%s:%d:",__FILE__,__LINE__);x
00202 #define MD2(x)
00203 
00204 //#define MD5(x) printk("%s:%d:",__FILE__,__LINE__);x
00205 #define MD5(x)
00206 //#define MD6(x) printk("%s:%d:",__FILE__,__LINE__);x
00207 #define MD6(x)
00208 //#define MD7(x) printk("%s:%d:",__FILE__,__LINE__);x
00209 #define MD7(x)
00210 
00211 //#define D0(x) printk("%s:%d:",__FILE__,__LINE__);x
00212 #define D0(x)
00213 
00214 //#define MD8(x) printk("%s:%d:",__FILE__,__LINE__);x
00215 #define MD8(x)
00216 //#define MD9(x) printk("%s:%d:",__FILE__,__LINE__);x
00217 #define MD9(x)
00218 //#define MD10(x) printk("%s:%d:",__FILE__,__LINE__);x
00219 #define MD10(x)
00220 //#define MD11(x) printk("%s:%d:",__FILE__,__LINE__);x
00221 #define MD11(x)
00222 //#define PRINTQTAB y
00223 //#if 0
00224 //#define JPEG_HEADER_SIZE        0x26f
00225 #define JPEG_HEADER_MAX_SIZE    0x300
00226 #if 0
00227 #define TRAILER_SIZE   0x02
00228 #define HEADER_YQTABLE 0x19
00229 #define HEADER_CQTABLE 0x5e
00230 
00231 #define HEADER_HEIGHT  0xa3
00232 #define HEADER_WIDTH   0xa5
00233 #endif
00234 /* really huge static DMA buffer (1288+8)*1032/3=445824 long-s */
00235 // DMA_SIZE - in 32-bit words, not bytes
00236 //static unsigned long ccam_dma_buf[CCAM_DMA_SIZE + PAGE_SIZE>>2)] __attribute__ ((aligned (PAGE_SIZE)));
00237 //static jpeg_header_current_size=jpeg_header_size; // not used?
00238 static unsigned long ccam_dma_buf[CCAM_DMA_SIZE + (PAGE_SIZE>>2)] __attribute__ ((aligned (PAGE_SIZE)));
00240 unsigned long  * ccam_dma_buf_ptr = NULL;
00241 unsigned long * ccam_dma =         NULL; 
00242 
00243 void init_ccam_dma_buf_ptr(void) {
00244     ccam_dma_buf_ptr = ccam_dma_buf;
00245     ccam_dma =         ccam_dma_buf; //&ccam_dma_buf[0]; Use in autoexposure
00246 }
00247 extern struct interframe_params_t frame_params; // cc353.c
00251 wait_queue_head_t circbuf_wait_queue;
00256 #define CIRCBUF_DRIVER_NAME "Elphel (R) Model 353 video buffer device driver"
00257 static struct file_operations circbuf_fops = {
00258    owner:    THIS_MODULE,
00259    llseek:   circbuf_all_lseek,
00260    read:     circbuf_all_read,
00261    write:    circbuf_all_write,
00262    ioctl:    circbuf_all_ioctl,
00263    open:     circbuf_all_open,
00264    mmap:     circbuf_all_mmap,
00265    poll:     circbuf_all_poll,
00266    release:  circbuf_all_release
00267 };
00268 
00269 // Read/write to circular buffer.  Needed to find out what Axis DMA is doing
00270 // also - jpeg header
00271 struct circbuf_pd {
00272     int       minor;        
00273     int       daemon_bit;   
00274 
00275     int       imageWidth;   
00276     int       imageHeight;  
00277     int       tolerated;    
00278     struct wait_queue *circbuf_wait_queue; 
00279 // something else to be added here?
00280 };
00281 // CMOSCAM_MINOR_HUFFMAN // huffman tables R/W
00282 int circbuf_all_open(struct inode *inode, struct file *filp) {
00283    int res;
00284  MD10(printk("circbuf_all_open, minor=0x%x\n",MINOR(inode->i_rdev)));
00285   switch (MINOR(inode->i_rdev)) {
00286     case  CMOSCAM_MINOR_CIRCBUF :
00287         res=circbuf_open(inode,filp);
00288         break;
00289     case  CMOSCAM_MINOR_JPEAGHEAD :
00290         res=jpeghead_open(inode,filp);
00291         break;
00292     case  CMOSCAM_MINOR_HUFFMAN :
00293         res=huffman_open(inode,filp);
00294         break;
00295     default:
00296 //       kfree(filp->private_data); // already allocated
00297        return -EINVAL;
00298   }
00299   return res;
00300 }
00301 int circbuf_all_release(struct inode *inode, struct file *filp) {
00302   int res=0;
00303   int p = MINOR(inode->i_rdev);
00304  MD10(printk("circbuf_all_release, minor=0x%x\n",p));
00305   switch ( p ) {
00306     case  CMOSCAM_MINOR_CIRCBUF :
00307 //        res=circbuf_release(inode,filp);
00308         break;
00309     case  CMOSCAM_MINOR_JPEAGHEAD :
00310 //        res=jpeghead_release(inode,filp);
00311         break;
00312     case  CMOSCAM_MINOR_HUFFMAN :
00313 //        res=huffman_release(inode,filp);
00314         break;
00315     default:
00316         return -EINVAL; 
00317     }
00318   if (filp->private_data) kfree(filp->private_data);
00319   return res;
00320 }
00321 
00322 loff_t circbuf_all_lseek(struct file * file, loff_t offset, int orig) {
00323      struct circbuf_pd * privData;
00324      privData = (struct circbuf_pd *) file->private_data;
00325  MD10(printk("circbuf_all_lseek, minor=0x%x\n",privData-> minor));
00326      switch (privData->minor) {
00327        case CMOSCAM_MINOR_CIRCBUF :    return  circbuf_lseek  (file, offset, orig);
00328        case CMOSCAM_MINOR_JPEAGHEAD :  return  jpeghead_lseek (file, offset, orig);
00329        case CMOSCAM_MINOR_HUFFMAN :    return  huffman_lseek  (file, offset, orig);
00330        default:                        return -EINVAL;
00331      }
00332 }
00333 
00334 ssize_t circbuf_all_read(struct file * file, char * buf, size_t count, loff_t *off) {
00335      struct circbuf_pd * privData;
00336      privData = (struct circbuf_pd *) file->private_data;
00337  MD10(printk("circbuf_all_read, minor=0x%x\n",privData-> minor));
00338      switch (privData->minor) {
00339        case CMOSCAM_MINOR_CIRCBUF :      return  circbuf_read   (file, buf, count, off);
00340        case CMOSCAM_MINOR_JPEAGHEAD :    return  jpeghead_read  (file, buf, count, off);
00341        case CMOSCAM_MINOR_HUFFMAN :      return  huffman_read  (file, buf, count, off);
00342        default:                          return -EINVAL;
00343     }
00344 }
00345 ssize_t circbuf_all_write(struct file * file, const char * buf, size_t count, loff_t *off) {
00346      struct circbuf_pd * privData;
00347      privData = (struct circbuf_pd *) file->private_data;
00348  MD10(printk("circbuf_all_write, minor=0x%x, count=%d, off=%d\n",privData-> minor, (int) count,(int)*off));
00349      switch (privData->minor) {
00350        case CMOSCAM_MINOR_CIRCBUF :       return  circbuf_write  (file, buf, count, off);
00351 //       case CMOSCAM_MINOR_JPEAGHEAD :     return  jpeghead_write (file, buf, count, off); // same as other - write header
00352        case CMOSCAM_MINOR_HUFFMAN :       return  huffman_write  (file, buf, count, off);
00353        default:                           return -EINVAL;
00354     }
00355 }
00356 
00357 
00358 int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma) {
00359      struct circbuf_pd * privData;
00360      privData = (struct circbuf_pd *) file->private_data;
00361  MD10(printk("circbuf_all_mmap, minor=0x%x\n",privData-> minor));
00362      switch (privData->minor) {
00363        case  CMOSCAM_MINOR_CIRCBUF :   return  circbuf_mmap   (file, vma);
00364        default: return -EINVAL;
00365     }
00366 }
00367 
00368 unsigned int circbuf_all_poll (struct file *file, poll_table *wait) {
00369      struct circbuf_pd * privData;
00370      privData = (struct circbuf_pd *) file->private_data;
00371  MD10(printk("circbuf_all_poll, minor=0x%x\n",privData-> minor));
00372      switch (privData->minor) {
00373        case  CMOSCAM_MINOR_CIRCBUF :
00374           return circbuf_poll (file, wait);
00375        default:                           return -EINVAL;
00376     }
00377 }
00378 
00379 int circbuf_all_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {
00380      struct circbuf_pd * privData;
00381      privData = (struct circbuf_pd *) filp->private_data;
00382      printk("\n========== IOCTL is not implemented in circbuf_all_ioctl, minor=0x%x, cmd=0x%x, _IOC_NR(cmd)=0x%x, arg=0x%x\n",privData-> minor, (int) cmd, _IOC_NR(cmd), (int) arg);
00383      return -EINVAL;
00384 }
00385 
00386 
00387 
00388 
00389 int circbuf_open(struct inode *inode, struct file *filp) { // set filesize
00390    struct circbuf_pd * privData;
00391    privData= (struct circbuf_pd *) kmalloc(sizeof(struct circbuf_pd),GFP_KERNEL);
00392    if (!privData) return -ENOMEM;
00393    filp->private_data = privData;
00394    privData-> minor=MINOR(inode->i_rdev);
00395 
00396    inode->i_size = ((CCAM_DMA_SIZE) << 2);
00397  MD10(printk("circbuf_open, inode->i_size=0x%x\n", (int)inode->i_size));
00398 
00400 //   circbuf_lseek(filp, LSEEK_CIRC_LAST, SEEK_END); //! position at last acquired frame, ignore result
00401    return 0;
00402 }
00403 
00443 
00444 
00445 
00446 
00447 
00448 
00449 int circbufValidPointer(int rp, struct interframe_params_t ** fpp) {
00450   if (rp & 0x1f) {  
00451        MD10(printk("circbufValidPointer: misaligned pointer\n"));
00452        return -2;
00453   }
00454   int wp=camSeqGetJPEG_wp();
00455   int p= rp >> 2; // index inccam_dma_buf
00456   struct interframe_params_t * fp;
00457   fp = (struct interframe_params_t *) &ccam_dma_buf[X313_BUFFSUB(p, 8)]; 
00458 
00459  MD10(printk("rp=0x%x (0x%x), offset=0x%x\n",rp,p,(int)&ccam_dma_buf[p]-(int)fp); dumpFrameParams(fp, "in circbufValidPointer:"));
00460 
00461   *fpp=fp;
00462  MD11(printk("p=0x%x , wp==0x%x\n",p,wp));
00463  if (p == wp) {
00464      return 0; // frame not yet acquired, fp - not valid
00465   }
00466   if (fp->signffff != 0xffff) { 
00467      MD10(printk("circbufValidPointer: signanure overwritten\n"));
00468      return -1;
00469   }
00470   if ((fp->timestamp_sec) & X313_LENGTH_MASK) return 0; 
00471   return 1;
00472    
00473 }
00474 
00475 loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
00476  //  orig 0: position from begning
00477  //  orig 1: relative from current
00478  //  orig 2: position from last  address
00479    int l = (CCAM_DMA_SIZE << 2);
00480    int fl=0;// frame length
00481    struct interframe_params_t * fp;
00482    int fvld=-1;
00483    int rp, bp, prev_p, preprev_p; //, p;
00484    int nf;   
00485    int nz=1; 
00486 MD12(int dbg_i);
00487 //   int pf; // previous frame
00488  MD11(printk("circbuf_lseek, offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
00489    switch(orig) {
00490    case SEEK_SET:
00491      file->f_pos = offset;
00492      break;
00493    case SEEK_CUR:
00494      if (offset) file->f_pos += offset;
00495      else if (circbufValidPointer(file->f_pos, &fp) <0 ) return -EINVAL; 
00496      break;
00497    case SEEK_END:
00498      if (offset <= 0) {
00499         file->f_pos = l + offset;
00500      } else { 
00501 
00502         switch (offset) {
00503           case LSEEK_CIRC_TORP:
00504               file->f_pos=camSeqGetJPEG_rp()<<2; 
00505           case LSEEK_CIRC_PREV:
00506           case LSEEK_CIRC_NEXT:
00507           case LSEEK_CIRC_SETP:
00508           case LSEEK_CIRC_VALID:
00509           case LSEEK_CIRC_READY:
00510           case LSEEK_CIRC_FREE:
00511           case LSEEK_CIRC_USED:
00512              if (((fvld=circbufValidPointer(file->f_pos, &fp))) <0 )
00513                 return -EINVAL; 
00514         }
00515         switch (offset) {
00516           case LSEEK_CIRC_FREE:
00517              bp=(file->f_pos - (camSeqGetJPEG_wp()<<2));
00518 //             return (bp>0)?bp:(bp+l); //!will return full buffer size if current pointer is a write pointer (waiting for the next frame)
00519              return (file->f_pos=(bp>0)?bp:(bp+l)); 
00520           case LSEEK_CIRC_USED:
00521              bp=((camSeqGetJPEG_wp()<<2) - file->f_pos);
00522 //             return (bp>=0)?bp:(bp+l); //!will return 0 if current pointer is a write pointer (waiting for the next frame)
00523              return (file->f_pos=(bp>0)?bp:(bp+l)); 
00524           case LSEEK_CIRC_TORP:
00525              break;
00526           case LSEEK_CIRC_TOWP:
00527              file->f_pos=camSeqGetJPEG_wp()<<2; // no checking if it is valid
00528              break;
00529           case LSEEK_CIRC_LAST:
00530              file->f_pos=camSeqGetJPEG_wp()<<2;
00531              fvld=circbufValidPointer(file->f_pos, &fp); 
00532           case LSEEK_CIRC_PREV:
00533              rp= file->f_pos >> 2;
00534              fl=ccam_dma_buf[X313_BUFFSUB(rp, 9)] ^ X313_LENGTH_MASK;
00535  MD11(printk("LSEEK_CIRC_PREV: rp=0x%x, fvld=%d, fl=0x%x\n", rp, fvld,fl));
00536              if (fl & X313_LENGTH_MASK) {
00537                 if (offset==LSEEK_CIRC_LAST) break; // just don't move pointer, leave it at write pointer and return no error
00538                 return -EOVERFLOW; 
00539              }
00540              bp = (X313_BUFFSUB(rp, X313_PADDED_FRAME(fl))<<2); // in bytes
00541  MD11(printk("LSEEK_CIRC_PREV: bp=0x%x (0x%x), circbufValidPointer=%d\n", bp, bp>>2,circbufValidPointer(rp>>2, &fp)));
00542              if (circbufValidPointer(bp, &fp) < 0 ) { 
00543                 if (offset==LSEEK_CIRC_LAST) break; // just don't move pointer, leave it at write pointer and return no error
00544                 return -EOVERFLOW; 
00545              }
00547              file->f_pos=bp;
00548              break;
00549           case LSEEK_CIRC_NEXT:
00550  MD11(printk("LSEEK_CIRC_NEXT: rp=0x%x, fvld=%d, fp->timestamp_sec=0x%x\n", file->f_pos >> 2, fvld, fp->timestamp_sec));
00551              if (fvld <=0) 
00552                 return -EOVERFLOW; 
00553              file->f_pos = X313_BUFFADD(file->f_pos >> 2, X313_PADDED_FRAME(fp->timestamp_sec)) <<2 ;// do it even if the next frame does not yet exist
00554              break;
00555           case LSEEK_CIRC_FIRST:
00556           case LSEEK_CIRC_SCND:
00558              rp=camSeqGetJPEG_wp();
00559              prev_p=rp;
00560              preprev_p=prev_p; // for second
00561              nf=0;
00562              nz=1;
00563              file->f_pos=rp<<2;
00564              while ((((fvld=circbufValidPointer(rp<<2, &fp))) >= 0) & (nz>=0)) {
00565                nf++;
00566 //               file->f_pos=rp<<2;
00567                preprev_p=prev_p; 
00568                prev_p=rp;        
00569                fl=ccam_dma_buf[X313_BUFFSUB(rp, 9)] ^ X313_LENGTH_MASK;
00570  MD11(printk("\nf=%d, rp=0x%x, fvld=%d, fl=0x%x\n",nf, rp, fvld, fl));
00571                if (fl & X313_LENGTH_MASK) break;  
00572 
00573                rp= X313_BUFFSUB(rp, X313_PADDED_FRAME(fl));
00574                if (rp > prev_p) nz-- ; // rolled through zero - make sure we'll not stuck in this loop forever
00575              }
00576 
00577  MD11(printk("after while{}: nf=%d, rp=0x%x, fvld=%d, fl=0x%x\n",nf, rp, fvld, fl));
00578              file->f_pos=((offset==LSEEK_CIRC_SCND)?preprev_p:prev_p) << 2;
00579              break;
00580           case LSEEK_CIRC_SETP:
00581              camSeqSetJPEG_rp(file->f_pos>>2);
00582              break;
00583           case LSEEK_CIRC_VALID:
00584              break;
00585           case LSEEK_CIRC_READY:
00586              if (fvld <=0) return -EINVAL; 
00587              break;
00588           case LSEEK_CIRC_WAIT:
00589               while (((fvld=circbufValidPointer(file->f_pos, &fp)))==0) { 
00590                 wait_event_interruptible (circbuf_wait_queue,(camSeqGetJPEG_wp()<<2)!=file->f_pos);
00591               }
00592               if (fvld < 0) return -ESPIPE;      
00593               return file->f_pos ; 
00594           default:
00595             if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) {
00596               wait_event_interruptible (circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
00597             }
00598         }
00599         return ( file->f_pos ); 
00600      }
00601      break;
00602    default:
00603       return -EINVAL;
00604    }
00605    // roll-over position
00606    while (file->f_pos < 0) file->f_pos+=l;
00607    while (file->f_pos > l) file->f_pos-=l;
00608    if ((orig !=SEEK_END) && (file->f_pos == l)) file->f_pos=0; 
00609    return  file->f_pos ;
00610 }
00611 
00612 ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t *off) {
00613    unsigned long p;
00614    char *char_pb = (char *)ccam_dma_buf;
00615    D(printk("circbuf_write\n"));
00617    p = *off;
00618    if(p >= (CCAM_DMA_SIZE << 2))
00619      p = (CCAM_DMA_SIZE << 2);
00620    if((p + count) > (CCAM_DMA_SIZE << 2)) { // truncate count
00621      count = (CCAM_DMA_SIZE << 2) - p;
00622    }
00623    if(count) {
00624      if(copy_from_user(&char_pb[p], buf, count))
00625         return -EFAULT;
00626      *off += count;
00627    }
00628    return count;
00629 }
00630 
00631 ssize_t circbuf_read(struct file * file, char * buf, size_t count, loff_t *off) {
00632   unsigned long p;
00633   char * char_pb = (char *) ccam_dma_buf;
00634   p = *off;
00635   D(printk("circbuf_read pos=%d,count=%d, off=%d\r\n",p,count,off ));
00636   if (p >= (CCAM_DMA_SIZE<<2))  p = (CCAM_DMA_SIZE<<2);
00637   if( (p + count) > (CCAM_DMA_SIZE<<2)) { // truncate count
00638     count = (CCAM_DMA_SIZE<<2) - p;
00639   }
00640   if (count) {
00641     if (copy_to_user(buf, &char_pb[p], count)) return -EFAULT;
00642 //    file->f_pos+=count;
00643     *off+=count;
00644   }
00645   return count;
00646 }
00647 int   circbuf_mmap   (struct file *file, struct vm_area_struct *vma) {
00648 
00649      int rslt;
00650 
00651      MD7(printk("vm_start=%lx\r\n",vma->vm_start));
00652      MD7(printk("vm_end=%lx\r\n",vma->vm_end));
00653      MD7(printk("vm_pgoff=%lx\r\n",vma->vm_pgoff));
00654      MD7(printk("vm_file=%lx\r\n",(unsigned long) (vma->vm_file)));
00655      MD7(printk("ccam_dma_buf=%lx\r\n",(unsigned long) (virt_to_phys (&ccam_dma_buf[0]))));
00656    /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
00657      rslt=remap_pfn_range(vma,
00658              vma->vm_start,
00659 //             ((unsigned long)(&ccam_dma_buf[0])) >> PAGE_SHIFT, // Should be page-aligned
00660              ((unsigned long) virt_to_phys(&ccam_dma_buf[0])) >> PAGE_SHIFT, // Should be page-aligned
00661              vma->vm_end-vma->vm_start,
00662              vma->vm_page_prot);
00663 
00664      MD7(printk("remap_pfn_range returned=%x\r\n",rslt));
00665      if (rslt) return -EAGAIN;
00666 //   vma->vm_ops = &simple_remap_vm_ops;
00667 //   simple_vma_open(vma);
00668      return 0;
00669 }
00676 unsigned int circbuf_poll (struct file *file, poll_table *wait) {
00677      struct interframe_params_t * fp;
00678      struct circbuf_pd * privData;
00679      privData = (struct circbuf_pd *) file->private_data;
00680      int rslt; 
00681  MD10(printk("circbuf_poll\n"));
00682      rslt= circbufValidPointer(file->f_pos, &fp);
00683      if        (rslt < 0) { 
00684  MD10(printk("circbuf_poll:invalid pointer\n"));
00685        return  POLLHUP ;
00686      } else if (rslt > 0) {
00687        return POLLIN | POLLRDNORM; 
00688      } else { 
00689        poll_wait(file, &circbuf_wait_queue, wait);
00692             if ((camSeqGetJPEG_wp()<<2)!=file->f_pos) return POLLIN | POLLRDNORM; 
00693     }
00694     return 0; // nothing ready
00695 }
00696 
00697 
00698 static int __init circbuf_all_init(void) {
00699    int res;
00700    MDF19(printk("\n"));
00701    res = register_chrdev(CIRCBUF_MAJOR, "circbuf_operations", &circbuf_fops);
00702    if(res < 0) {
00703      printk(KERN_ERR "\ncircbuf_all_init: couldn't get a major number %d.\n",CIRCBUF_MAJOR);
00704      return res;
00705    }
00706 
00707    MDF19(printk("init_waitqueue_head()\n"));
00708    init_waitqueue_head(&circbuf_wait_queue);
00709    MDF19(printk("jpeg_htable_init()\n"));
00710    jpeg_htable_init ();         
00711    printk(CIRCBUF_DRIVER_NAME"- %d\n",CIRCBUF_MAJOR);
00712    return 0;
00713 }
00714 
00715 
00716 module_init(circbuf_all_init);
00717 MODULE_LICENSE("GPLv3.0");
00718 MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
00719 MODULE_DESCRIPTION(CIRCBUF_DRIVER_NAME);
00720 

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