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
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
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
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"
00170 #include "framepars.h"
00171
00172 #include "x3x3.h"
00173
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
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
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
00200 #define MD1(x)
00201
00202 #define MD2(x)
00203
00204
00205 #define MD5(x)
00206
00207 #define MD6(x)
00208
00209 #define MD7(x)
00210
00211
00212 #define D0(x)
00213
00214
00215 #define MD8(x)
00216
00217 #define MD9(x)
00218
00219 #define MD10(x)
00220
00221 #define MD11(x)
00222
00223
00224
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
00235
00236
00237
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;
00246 }
00247 extern struct interframe_params_t frame_params;
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
00270
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
00280 };
00281
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
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
00308 break;
00309 case CMOSCAM_MINOR_JPEAGHEAD :
00310
00311 break;
00312 case CMOSCAM_MINOR_HUFFMAN :
00313
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
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) {
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
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;
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;
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
00477
00478
00479 int l = (CCAM_DMA_SIZE << 2);
00480 int fl=0;
00481 struct interframe_params_t * fp;
00482 int fvld=-1;
00483 int rp, bp, prev_p, preprev_p;
00484 int nf;
00485 int nz=1;
00486 MD12(int dbg_i);
00487
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
00519 return (file->f_pos=(bp>0)?bp:(bp+l));
00520 case LSEEK_CIRC_USED:
00521 bp=((camSeqGetJPEG_wp()<<2) - file->f_pos);
00522
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;
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;
00538 return -EOVERFLOW;
00539 }
00540 bp = (X313_BUFFSUB(rp, X313_PADDED_FRAME(fl))<<2);
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;
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 ;
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;
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
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-- ;
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
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)) {
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)) {
00638 count = (CCAM_DMA_SIZE<<2) - p;
00639 }
00640 if (count) {
00641 if (copy_to_user(buf, &char_pb[p], count)) return -EFAULT;
00642
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
00657 rslt=remap_pfn_range(vma,
00658 vma->vm_start,
00659
00660 ((unsigned long) virt_to_phys(&ccam_dma_buf[0])) >> PAGE_SHIFT,
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
00667
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;
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