Commit e14c7478 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Add multichannel support to circbuf.c, fix formatting

parent b6edd8a4
/** @file circbuf.c /** @file circbuf.c
* *
* @brief drivers to manipulate large circular buffer that holds compressed * @brief Drivers to manipulate large circular buffer that holds compressed
* images/video. Buffer frame data is filled in by the FPGA, frame pointers and * images/video. Buffer frame data is filled in by the FPGA, frame pointers and
* essential frames metadata filled during servicing of the interrupts. * essential frames metadata filled during servicing of the interrupts.
* *
...@@ -71,20 +71,17 @@ ...@@ -71,20 +71,17 @@
#include "x393_macro.h" #include "x393_macro.h"
#include "x393.h" #include "x393.h"
#define CIRCBUF_DRIVER_NAME "circbuf driver"
/** Wait queue for the processes waiting for a new frame to appear in the circular buffer */
wait_queue_head_t circbuf_wait_queue;
struct circbuf_priv_t circbuf_priv[IMAGE_CHN_NUM]; struct circbuf_priv_t circbuf_priv[IMAGE_CHN_NUM];
struct circbuf_priv_t *circbuf_priv_ptr = circbuf_priv; struct circbuf_priv_t *circbuf_priv_ptr = circbuf_priv;
static struct device *g_dev_ptr; static struct device *g_dev_ptr;
static const struct of_device_id elphel393_circbuf_of_match[]; static const struct of_device_id elphel393_circbuf_of_match[];
/* really huge static DMA buffer (1288+8)*1032/3=445824 long-s */
// DMA_SIZE - in 32-bit words, not bytes
//static unsigned long ccam_dma_buf[CCAM_DMA_SIZE + (PAGE_SIZE>>2)] __attribute__ ((aligned (PAGE_SIZE)));
static unsigned long *ccam_dma_buf = NULL;
//!Without "static" system hangs after "Uncompressing Linux...
unsigned long * ccam_dma_buf_ptr = NULL;
//EXPORT_SYMBOL_GPL(ccam_dma_buf_ptr);
//unsigned long * ccam_dma = NULL; //! still used in autoexposure or something - why is in needed there?
int init_ccam_dma_buf_ptr(struct platform_device *pdev) int init_ccam_dma_buf_ptr(struct platform_device *pdev)
{ {
...@@ -92,8 +89,7 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev) ...@@ -92,8 +89,7 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
dma_addr_t dma_handle; dma_addr_t dma_handle;
const size_t dma_size = (CCAM_DMA_SIZE + (PAGE_SIZE >> 2)) * sizeof(int); const size_t dma_size = (CCAM_DMA_SIZE + (PAGE_SIZE >> 2)) * sizeof(int);
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
//ccam_dma_buf_ptr = ccam_dma_buf; unsigned long *ccam_dma_buf_ptr = NULL;
//ccam_dma = ccam_dma_buf; //&ccam_dma_buf[0]; Use in autoexposure
// use Elphel_buf if it was allocated // use Elphel_buf if it was allocated
if (pElphel_buf != NULL) { if (pElphel_buf != NULL) {
...@@ -109,10 +105,8 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev) ...@@ -109,10 +105,8 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
dev_info(dev, "%d bytes of DMA memory allocated at address 0x%08p", dma_size , dma_handle); dev_info(dev, "%d bytes of DMA memory allocated at address 0x%08p", dma_size , dma_handle);
} }
} }
ccam_dma_buf = ccam_dma_buf_ptr;
// set circbuf size in bytes // set circular buffer size in bytes
//set_globalParam(G_CIRCBUFSIZE, pElphel_buf->size * PAGE_SIZE);
set_globalParam(G_CIRCBUFSIZE, CCAM_DMA_SIZE); set_globalParam(G_CIRCBUFSIZE, CCAM_DMA_SIZE);
for (i = 0; i < IMAGE_CHN_NUM; i++) { for (i = 0; i < IMAGE_CHN_NUM; i++) {
...@@ -123,231 +117,189 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev) ...@@ -123,231 +117,189 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
return 0; return 0;
} }
static inline unsigned int minor_to_chn(int minor) /**
* @brief Converts file minor number to image compressor channel.
*
* This function assumes that the least significant nibble of minor contains image compressor channel number and
* next nibble contains device type. Channel numbers and device type are defined in #driver_numbers.h
* @param[in] minor file minor number
* @param[out] dev_type pointer to a variable which will hold device type or NULL if this value is not needed
* @return compressor channel number in the range [0..#IMAGE_CHN_NUM)
*/
static inline unsigned int minor_to_chn(unsigned int minor, unsigned int *dev_type)
{ {
//return minor - CIRCBUF_MINOR_CHN_OFFSET; if (dev_type != NULL) {
if ((minor & 0xf0) == CIRCBUF_MINOR || (minor & 0xf0) == HUFFMAN_MINOR || (minor & 0xf0) == JPEGHEAD_MINOR)
*dev_type = minor & 0xf0;
else
*dev_type = 0;
}
if ((minor & 0x0f) < IMAGE_CHN_NUM)
return minor & 0x0f;
else
return 0; return 0;
} }
//extern struct interframe_params_t frame_params; // cc353.c
/*!======================================================================================
*! Wait queue for the processes waiting for a new frame to appear in the circular buffer
*!======================================================================================*/
wait_queue_head_t circbuf_wait_queue;
/*!=========================================================================================================
*! circbuf top level device drivers. Minors are the same as before
*! CMOSCAM_MINOR_CIRCBUF, CMOSCAM_MINOR_JPEAGHEAD - just a new major
*!========================================================================================================*/
#define CIRCBUF_DRIVER_NAME "Elphel (R) Model 353 video buffer device driver"
// Read/write to circular buffer. Needed to find out what Axis DMA is doing
// also - jpeg header
struct circbuf_pd {
int minor; /// should be the first, same as in jpeghead_pd
int daemon_bit; /// poll() will produce POLLHUP if this bit is >=0 (set through lseek (, LSEEK_DAEMON_CIRCBUF,SEEK_END)
/// and the corresponding bit in P_DAEMON_EN goes 0
int imageWidth; /// image width to compare to current. G_SKIP_DIFF_FRAME
int imageHeight; /// image height to compare to current. G_SKIP_DIFF_FRAME
int tolerated; /// number of frames with different size tolerated
struct wait_queue *circbuf_wait_queue; ///NOTE: not used at all?
// something else to be added here?
};
// CMOSCAM_MINOR_HUFFMAN // huffman tables R/W
int circbuf_all_open(struct inode *inode, struct file *filp) int circbuf_all_open(struct inode *inode, struct file *filp)
{ {
int res; int res;
int minor = MINOR(inode->i_rdev); unsigned int minor = MINOR(inode->i_rdev);
unsigned int dev_type;
dev_dbg(g_dev_ptr, "circbuf_all_open, minor = 0x%x\n", minor); dev_dbg(g_dev_ptr, "circbuf_all_open, minor = 0x%x\n", minor);
switch (MINOR(inode->i_rdev)) { minor_to_chn(minor, &dev_type);
case CMOSCAM_MINOR_CIRCBUF : switch (dev_type) {
res=circbuf_open(inode,filp); case CIRCBUF_MINOR:
res = circbuf_open(inode, filp);
break; break;
case CMOSCAM_MINOR_JPEAGHEAD : case JPEGHEAD_MINOR:
res=jpeghead_open(inode,filp); res = jpeghead_open(inode, filp);
break; break;
case CMOSCAM_MINOR_HUFFMAN : case HUFFMAN_MINOR:
res=huffman_open(inode,filp); res = huffman_open(inode, filp);
break; break;
default: default:
// kfree(filp->private_data); // already allocated
return -EINVAL; return -EINVAL;
} }
return res; return res;
} }
int circbuf_all_release(struct inode *inode, struct file *filp) { int circbuf_all_release(struct inode *inode, struct file *filp)
{
int res=0; int res=0;
int p = MINOR(inode->i_rdev); unsigned int minor = MINOR(inode->i_rdev);
dev_dbg(g_dev_ptr, "minor = 0x%x\n", p); unsigned int dev_type;
switch ( p ) { dev_dbg(g_dev_ptr, "minor = 0x%x\n", minor);
case CMOSCAM_MINOR_CIRCBUF :
// res=circbuf_release(inode,filp); minor_to_chn(minor, &dev_type);
switch (dev_type) {
case CIRCBUF_MINOR:
// res=circbuf_release(inode,filp);
break; break;
case CMOSCAM_MINOR_JPEAGHEAD : case JPEGHEAD_MINOR:
// res=jpeghead_release(inode,filp); // res=jpeghead_release(inode,filp);
break; break;
case CMOSCAM_MINOR_HUFFMAN : case HUFFMAN_MINOR:
// res=huffman_release(inode,filp); // res=huffman_release(inode,filp);
break; break;
default: default:
return -EINVAL; //! do not need to free anything - "wrong number" return -EINVAL;
} }
if (filp->private_data) kfree(filp->private_data); if (filp->private_data) kfree(filp->private_data);
return res; return res;
} }
loff_t circbuf_all_lseek(struct file * file, loff_t offset, int orig) loff_t circbuf_all_lseek(struct file *file, loff_t offset, int orig)
{ {
struct circbuf_pd * privData;
privData = (struct circbuf_pd *) file->private_data;
struct interframe_params_t *fp = NULL;
int rp; int rp;
int minor = privData->minor; struct interframe_params_t *fp = NULL;
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int dev_type;
unsigned int chn = minor_to_chn(minor, &dev_type);
dev_dbg(g_dev_ptr, "circbuf_all_lseek, minor = 0x%x\n", minor); dev_dbg(g_dev_ptr, "circbuf_all_lseek, minor = 0x%x\n", minor);
switch (minor) {
case CMOSCAM_MINOR_CIRCBUF : switch (dev_type) {
case CIRCBUF_MINOR:
return circbuf_lseek(file, offset, orig); return circbuf_lseek(file, offset, orig);
case CMOSCAM_MINOR_JPEAGHEAD : case JPEGHEAD_MINOR:
if (orig == SEEK_END && offset > 0) { if (orig == SEEK_END && offset > 0) {
rp = BYTE2DW(offset) & (~7); // convert to index to long, align to 32-bytes rp = BYTE2DW(offset) & (~7); // convert to index to long, align to 32-bytes
//fp = (struct interframe_params_t *) &ccam_dma_buf_ptr[X313_BUFFSUB(rp, 8)]; //! 32 bytes before the frame pointer, may roll-over to the end of ccam_dma_buf_ptr fp = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[X393_BUFFSUB(rp, 8)];
fp = (struct interframe_params_t *) &circbuf_priv[minor_to_chn(minor)].buf_ptr[X393_BUFFSUB(rp, 8)];
} }
return jpeghead_lseek(file, offset, orig, fp); return jpeghead_lseek(file, offset, orig, fp);
case CMOSCAM_MINOR_HUFFMAN : case HUFFMAN_MINOR:
return huffman_lseek(file, offset, orig); return huffman_lseek(file, offset, orig);
default: default:
return -EINVAL; return -EINVAL;
} }
} }
ssize_t circbuf_all_read(struct file * file, char * buf, size_t count, loff_t *off) { ssize_t circbuf_all_read(struct file *file, char *buf, size_t count, loff_t *off)
struct circbuf_pd * privData; {
privData = (struct circbuf_pd *) file->private_data; unsigned int minor = MINOR(file->f_inode->i_rdev);
dev_dbg(g_dev_ptr, "minor = 0x%x\n", privData->minor); unsigned int dev_type;
switch (privData->minor) { dev_dbg(g_dev_ptr, "minor = 0x%x\n", minor);
case CMOSCAM_MINOR_CIRCBUF : return circbuf_read (file, buf, count, off);
case CMOSCAM_MINOR_JPEAGHEAD : return jpeghead_read (file, buf, count, off); minor_to_chn(minor, &dev_type);
case CMOSCAM_MINOR_HUFFMAN : return huffman_read (file, buf, count, off); switch (dev_type) {
default: return -EINVAL; case CIRCBUF_MINOR:
return circbuf_read(file, buf, count, off);
case JPEGHEAD_MINOR:
return jpeghead_read(file, buf, count, off);
case HUFFMAN_MINOR:
return huffman_read(file, buf, count, off);
default:
return -EINVAL;
} }
} }
ssize_t circbuf_all_write(struct file * file, const char * buf, size_t count, loff_t *off) {
struct circbuf_pd * privData; ssize_t circbuf_all_write(struct file *file, const char *buf, size_t count, loff_t *off)
privData = (struct circbuf_pd *) file->private_data; {
dev_dbg(g_dev_ptr, "minor = 0x%x, count = %d, off = %d\n", privData->minor, (int)count, (int)*off); unsigned int minor = MINOR(file->f_inode->i_rdev);
switch (privData->minor) { unsigned int dev_type;
case CMOSCAM_MINOR_CIRCBUF : return circbuf_write (file, buf, count, off); dev_dbg(g_dev_ptr, "minor = 0x%x, count = %d, off = %d\n", minor, (int)count, (int)*off);
// case CMOSCAM_MINOR_JPEAGHEAD : return jpeghead_write (file, buf, count, off); // same as other - write header
case CMOSCAM_MINOR_HUFFMAN : return huffman_write (file, buf, count, off); minor_to_chn(minor, &dev_type);
default: return -EINVAL; switch (dev_type) {
case CIRCBUF_MINOR:
return circbuf_write (file, buf, count, off);
case JPEGHEAD_MINOR:
// no method for this module
return -EINVAL;
case HUFFMAN_MINOR:
return huffman_write (file, buf, count, off);
default:
return -EINVAL;
} }
} }
int circbuf_all_mmap(struct file *file, struct vm_area_struct *vma)
{
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int dev_type;
dev_dbg(g_dev_ptr, "minor = 0x%x\n", minor);
int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma) { minor_to_chn(minor, &dev_type);
struct circbuf_pd * privData; switch (dev_type) {
privData = (struct circbuf_pd *) file->private_data; case CIRCBUF_MINOR:
dev_dbg(g_dev_ptr, "minor = 0x%x\n", privData->minor); return circbuf_mmap(file, vma);
switch (privData->minor) { default:
case CMOSCAM_MINOR_CIRCBUF : return circbuf_mmap (file, vma); return -EINVAL;
default: return -EINVAL;
} }
} }
unsigned int circbuf_all_poll (struct file *file, poll_table *wait) { unsigned int circbuf_all_poll (struct file *file, poll_table *wait)
struct circbuf_pd * privData; {
privData = (struct circbuf_pd *) file->private_data; unsigned int minor = MINOR(file->f_inode->i_rdev);
dev_dbg(g_dev_ptr, "minor = 0x%x\n", privData->minor); unsigned int dev_type;
switch (privData->minor) { dev_dbg(g_dev_ptr, "minor = 0x%x\n", minor);
case CMOSCAM_MINOR_CIRCBUF :
return circbuf_poll (file, wait);
default: return -EINVAL;
}
}
int circbuf_all_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { minor_to_chn(minor, &dev_type);
struct circbuf_pd * privData; switch (dev_type) {
privData = (struct circbuf_pd *) filp->private_data; case CIRCBUF_MINOR:
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); return circbuf_poll(file, wait);
default:
return -EINVAL; return -EINVAL;
}
} }
int circbuf_open(struct inode *inode, struct file *filp)
{
int circbuf_open(struct inode *inode, struct file *filp) { // set filesize
struct circbuf_pd * privData;
privData= (struct circbuf_pd *) kmalloc(sizeof(struct circbuf_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
filp->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
//inode->i_size = ((CCAM_DMA_SIZE) << 2);
inode->i_size = CCAM_DMA_SIZE; inode->i_size = CCAM_DMA_SIZE;
dev_dbg(g_dev_ptr, "inode->i_size = 0x%x\n"); dev_dbg(g_dev_ptr, "inode->i_size = 0x%x\n");
//!should be removed (or else you can not ftp file - it will start from WP)
// circbuf_lseek(filp, LSEEK_CIRC_LAST, SEEK_END); //! position at last acquired frame, ignore result
return 0; return 0;
} }
/*!=============================================================================================
*! Overloading lseek with additional functionality (to avoid ioctls)
*! with orig==SEEK_END lseek will treat (offset>0) as a command
*! to manipulate frame pointer(s) or wait for the image to be ready
*! using these commands
*! LSEEK_CIRC_TORP .- set filepointer to global (shared) read pointer
*! LSEEK_CIRC_TOWP - set filepointer to FPGA write pointer (next frame to be acquired)
*! LSEEK_CIRC_PREV - move pointer to the previous frame, return -EOVERFLOW if there are none
*! LSEEK_CIRC_NEXT - advance pointer to the next frame, return -EOVERFLOW if was already
*! at the last
*! LSEEK_CIRC_LAST - move pointer to the last acquired frame (default after open)
*! (it is combination of 2+3)
*! LSEEK_CIRC_FIRST - move pointer to the first acquired frame. It s not safe to rely
*! on this pointer if more frames are expected - next incoming frame
*! can overwrite this one.
*! LSEEK_CIRC_SCND - move pointer to the second oldest acquired frame. A slightly safer
*! to use instead of LSEEK_CIRC_FIRST when constant acquisition is on
*! and sensor provides new frames - this frame will likely survive longer
*! LSEEK_CIRC_SETP - save current pointer to global read pointer
*! LSEEK_CIRC_VALID - verify that the frame at current location is valid (not overrun in the buffer)
*! Returns file pointer if valid, else - -1
*! LSEEK_CIRC_READY - verify frame at current loacation is available (valid and acquired)
*! Returns file pointer if ready, else - -1
*! LSEEK_CIRC_WAIT - sleep until next frame is acquired
*! All commands but (LSEEK_CIRC_TOWP,LSEEK_CIRC_LAST,LSEEK_CIRC_FIRST) will return -EINVAL if read
*! pointer is not valid (i.e buffer was overrun and data pointed is lost). if success they return
*! the current (byte *) to the start of the frame data (parameters are at
*! offsett =-32 from it)
*! (0, SEEK_CUR) also verifies that the header is not overwritten. It can be used
*! after buffering frame data to verify you got it all correctly
*! SEEK_CUR also supports the circular nature of the buffer and rolls over if needed
*! Additional commands for SEEK_END (they _DO_ modify the current file pointer !)
*! LSEEK_CIRC_FREE - returnes remaining memory in circbuf from the current file pointer,
*! or -EINVAL if the pointer is invalid. As this command uses the buffer write pointer
*! that is updated only when the complete frame is in the buffer, the actual
*! free memory may be less by a whole frame if compressor is running.
*! LSEEK_CIRC_USED - returnes memory used in the in circbuf from the current file pointer,
*! or -EINVAL if the pointer is invalid
*!=============================================================================================*/
//!returns 0 if rp is a valid read ponter
//! returns 1 if there is a frame at this address
//! returns 0 if the pointer is for the frame yet to be acquired
//! returns -1 if there is no frame at this index
//! returns -2 if the rp is not 32-bytes aligned
//!sets *fpp to the frame header, including signature and length
void dump_interframe_params(struct interframe_params_t *params, int offset) void dump_interframe_params(struct interframe_params_t *params, int offset)
{ {
dev_dbg(g_dev_ptr, "Dump of interframe parameters at offset 0x%x:\n", offset); dev_dbg(g_dev_ptr, "Dump of interframe parameters at offset 0x%x:\n", offset);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, params, sizeof(struct interframe_params_t)); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, params, sizeof(struct interframe_params_t));
} }
/**
* @brief
*/
unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chunk_offset) unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chunk_offset)
{ {
unsigned long len32; unsigned long len32;
...@@ -365,8 +317,17 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun ...@@ -365,8 +317,17 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun
return len32; return len32;
} }
// rp is byte offset /**
int circbufValidPointer(int rp, struct interframe_params_t ** fpp, unsigned int chn) * @brief Check that read pointer is valid
* @param[in] rp read pointer to be checked; this pointer is in bytes
* @param[out] fpp pointer to #interframe_params_t structure, this pointer will be set to
* frame header before \e rp and will point to its parameters
* @param[in] chn specify compressor channel number which pointer should be checked
* @return 0 if the pointer is for the frame yet to be acquired, 1 if there is a valid frame at this address,
* -1 if there is no frame at this index, -2 if the pointer is not 32-bytes aligned
* sets *fpp to the frame header, including signature and length
*/
int circbuf_valid_ptr(int rp, struct interframe_params_t **fpp, unsigned int chn)
{ {
int last_image_chunk; int last_image_chunk;
unsigned int sec; unsigned int sec;
...@@ -375,7 +336,8 @@ int circbufValidPointer(int rp, struct interframe_params_t ** fpp, unsigned int ...@@ -375,7 +336,8 @@ int circbufValidPointer(int rp, struct interframe_params_t ** fpp, unsigned int
unsigned int len32 = get_image_length(DW2BYTE(wp), chn, &last_image_chunk); unsigned int len32 = get_image_length(DW2BYTE(wp), chn, &last_image_chunk);
struct interframe_params_t *fp; struct interframe_params_t *fp;
if (rp & 0x1f) { //!rp is not 32-bytes aligned if (rp & 0x1f) {
// rp is not 32-bytes aligned
dev_dbg(g_dev_ptr, "misaligned pointer rp = 0x%x for channel %d\n", rp, chn); dev_dbg(g_dev_ptr, "misaligned pointer rp = 0x%x for channel %d\n", rp, chn);
return -2; return -2;
} }
...@@ -396,39 +358,79 @@ int circbufValidPointer(int rp, struct interframe_params_t ** fpp, unsigned int ...@@ -396,39 +358,79 @@ int circbufValidPointer(int rp, struct interframe_params_t ** fpp, unsigned int
return 1; return 1;
} }
loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { /**
unsigned int len32; * @brief Reposition read/write file offset
*
* This function is overloaded with additional functionality in order to avoid ioctls.
* In case user-space program set <em>orig == SEEK_END</em>, \e lseek will treat (offset > 0) as a command
* to manipulate frame pointer(s) or wait for the image to be ready using these commands:
*
* LSEEK_CIRC_TORP - set file pointer to global (shared) read pointer;
* LSEEK_CIRC_TOWP - set file pointer to FPGA write pointer (next frame to be acquired);
* LSEEK_CIRC_PREV - move pointer to the previous frame, return \e -EOVERFLOW if there are none;
* LSEEK_CIRC_NEXT - advance pointer to the next frame, return \e -EOVERFLOW if it was at the last frame
* LSEEK_CIRC_LAST - move pointer to the last acquired frame (default after open), this is a combination
* of LSEEK_CIRC_TOWP and LSEEK_CIRC_PREV;
* LSEEK_CIRC_FIRST - move pointer to the first acquired frame. It s not safe to rely
* on this pointer if more frames are expected - next incoming frame
* can overwrite this one;
* LSEEK_CIRC_SCND - move pointer to the second oldest acquired frame. A slightly safer
* to use instead of LSEEK_CIRC_FIRST when constant acquisition is on
* and sensor provides new frames - this frame will likely survive longer;
* LSEEK_CIRC_SETP - save current pointer to global read pointer
* LSEEK_CIRC_VALID - verify that the frame at current location is valid (not overrun in the buffer).
* Returns file pointer if it is valid and -1 otherwise;
* LSEEK_CIRC_READY - verify frame at current location is available (valid and acquired).
* Returns file pointer if it is ready or -1 otherwise
* LSEEK_CIRC_WAIT - sleep until next frame is acquired.
* All commands but (LSEEK_CIRC_TOWP, LSEEK_CIRC_LAST, LSEEK_CIRC_FIRST) will return -EINVAL if read
* pointer is not valid (i.e buffer was overrun and data pointed is lost). In case of success, they return
* current (byte *) to the start of the frame data (parameters are at offset - 32 from it).
* (0, SEEK_CUR) also verifies that the header is not overwritten. It can be used after buffering frame data to
* verify you got it all correctly.
*
* SEEK_CUR also supports the circular nature of the buffer and rolls over if needed.
*
* Additional commands for SEEK_END (they _DO_ modify the current file pointer):
* LSEEK_CIRC_FREE - returns remaining memory in circbuf from the current file pointer,
* or -EINVAL if the pointer is invalid. As this command uses the buffer write pointer
* that is updated only when the complete frame is in the buffer, the actual
* free memory may be less by a whole frame if compressor is running.
* LSEEK_CIRC_USED - returns memory used in the in circbuf from the current file pointer,
* or -EINVAL if the pointer is invalid
* @param[in] file pointer to \e file structure
* @param[in] offset offset inside buffer in bytes
* @param[in] orig origin
* @return current file pointer position if operation was successful and error code otherwise
*/
loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
{
unsigned int len32 = 0;
int inserted_bytes; int inserted_bytes;
int last_image_chunk; int last_image_chunk;
int img_start, next_img, padded_frame; int img_start, next_img, padded_frame;
unsigned int minor = MINOR(file->f_inode->i_rdev); unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor); unsigned int chn = minor_to_chn(minor, NULL);
// orig 0: position from begning
// orig 1: relative from current
// orig 2: position from last address
int l = CCAM_DMA_SIZE;
int fl=0;// frame length
struct interframe_params_t * fp; struct interframe_params_t * fp;
int fvld=-1; int fvld = -1;
int rp, bp; //, p; int rp, bp;
// int pf; // previous frame
dev_dbg(g_dev_ptr, "start processing LSEEK operation: offset = 0x%x, orig = 0x%x\n",(int) offset, (int) orig); dev_dbg(g_dev_ptr, "start processing LSEEK operation: offset = 0x%x, orig = 0x%x\n",(int) offset, (int) orig);
switch(orig) {
switch (orig) {
case SEEK_SET: case SEEK_SET:
file->f_pos = offset; file->f_pos = offset;
break; break;
case SEEK_CUR: case SEEK_CUR:
if (offset) file->f_pos += offset; if (offset) file->f_pos += offset;
else if (circbufValidPointer(file->f_pos, &fp, chn) <0 ) return -EINVAL; //!no frames at the specified location or pointer is not 32-byte aligned else if (circbuf_valid_ptr(file->f_pos, &fp, chn) < 0 ) return -EINVAL; //!no frames at the specified location or pointer is not 32-byte aligned
break; break;
case SEEK_END: case SEEK_END:
if (offset <= 0) { if (offset <= 0) {
file->f_pos = l + offset; file->f_pos = CCAM_DMA_SIZE + offset;
} else { //! New functionality } else {
//!verify the frame pointer // verify current frame pointer
switch (offset) { switch (offset) {
case LSEEK_CIRC_TORP: case LSEEK_CIRC_TORP:
//file->f_pos=camSeqGetJPEG_rp()<<2; //! set file pointer to global read pointer, and proceed
file->f_pos = camseq_get_jpeg_rp(chn) << 2; file->f_pos = camseq_get_jpeg_rp(chn) << 2;
case LSEEK_CIRC_PREV: case LSEEK_CIRC_PREV:
case LSEEK_CIRC_NEXT: case LSEEK_CIRC_NEXT:
...@@ -437,28 +439,26 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { ...@@ -437,28 +439,26 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
case LSEEK_CIRC_READY: case LSEEK_CIRC_READY:
case LSEEK_CIRC_FREE: case LSEEK_CIRC_FREE:
case LSEEK_CIRC_USED: case LSEEK_CIRC_USED:
if ((fvld = circbufValidPointer(file->f_pos, &fp, chn)) < 0) if ((fvld = circbuf_valid_ptr(file->f_pos, &fp, chn)) < 0)
return -EINVAL; //!no frames at the specified location return -EINVAL; // no frames at the specified location
} }
switch (offset) { switch (offset) {
case LSEEK_CIRC_FREE: case LSEEK_CIRC_FREE:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_FREE: checking remaining memory in circbuf\n"); dev_dbg(g_dev_ptr, "LSEEK_CIRC_FREE: checking remaining memory in circbuf\n");
bp = file->f_pos - (camseq_get_jpeg_wp(chn) << 2); bp = file->f_pos - (camseq_get_jpeg_wp(chn) << 2);
return (file->f_pos = (bp > 0) ? bp : (bp + l)); //!Has a side effect of moving a file pointer! return (file->f_pos = (bp > 0) ? bp : (bp + CCAM_DMA_SIZE)); //!Has a side effect of moving a file pointer!
case LSEEK_CIRC_USED: case LSEEK_CIRC_USED:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_USED: checking used memory in circbuf\n"); dev_dbg(g_dev_ptr, "LSEEK_CIRC_USED: checking used memory in circbuf\n");
bp = (camseq_get_jpeg_wp(chn) << 2) - file->f_pos; bp = (camseq_get_jpeg_wp(chn) << 2) - file->f_pos;
return (file->f_pos = (bp > 0) ? bp : (bp + l)); //!Has a side effect of moving a file pointer! return (file->f_pos = (bp > 0) ? bp : (bp + CCAM_DMA_SIZE)); //!Has a side effect of moving a file pointer!
case LSEEK_CIRC_TORP: case LSEEK_CIRC_TORP:
// no actions to be done here, the pointer was set on previous step // no actions to be done here, the pointer was set on previous step
break; break;
case LSEEK_CIRC_TOWP: case LSEEK_CIRC_TOWP:
//file->f_pos=camSeqGetJPEG_wp()<<2; // no checking if it is valid
file->f_pos = camseq_get_jpeg_wp(chn) << 2; file->f_pos = camseq_get_jpeg_wp(chn) << 2;
break; break;
case LSEEK_CIRC_LAST: case LSEEK_CIRC_LAST:
next_img = camseq_get_jpeg_wp(chn) << 2; next_img = camseq_get_jpeg_wp(chn) << 2;
//fvld = circbufValidPointer(next_img, &fp, chn);
dev_dbg(g_dev_ptr, "LSEEK_CIRC_LAST: next_img = 0x%x, fvld = %d\n", next_img, fvld); dev_dbg(g_dev_ptr, "LSEEK_CIRC_LAST: next_img = 0x%x, fvld = %d\n", next_img, fvld);
dev_dbg(g_dev_ptr, "mem dump of last 0x40 bytes in buffer number %d\n", chn); dev_dbg(g_dev_ptr, "mem dump of last 0x40 bytes in buffer number %d\n", chn);
...@@ -471,17 +471,16 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { ...@@ -471,17 +471,16 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
return -EOVERFLOW; return -EOVERFLOW;
} }
len32 &= FRAME_LENGTH_MASK; len32 &= FRAME_LENGTH_MASK;
//inserted_bytes = ((CHUNK_SIZE - (((len32 % CHUNK_SIZE) + CCAM_MMAP_META) % CHUNK_SIZE) - ADJUSTMENT) % CHUNK_SIZE ) + ADJUSTMENT;
img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32); img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
dev_dbg(g_dev_ptr, "calculated start address = 0x%x, length = 0x%x\n", img_start, len32); dev_dbg(g_dev_ptr, "calculated start address = 0x%x, length = 0x%x\n", img_start, len32);
if (circbufValidPointer(img_start, &fp, chn) < 0) if (circbuf_valid_ptr(img_start, &fp, chn) < 0)
return -EOVERFLOW; return -EOVERFLOW;
file->f_pos = img_start; file->f_pos = img_start;
dev_dbg(g_dev_ptr, "LSEEK_CIRC_LAST: moving file->f_pos to 0x%llx\n", file->f_pos); dev_dbg(g_dev_ptr, "LSEEK_CIRC_LAST: moving file->f_pos to 0x%llx\n", file->f_pos);
break; break;
case LSEEK_CIRC_PREV: case LSEEK_CIRC_PREV:
next_img = camseq_get_jpeg_wp(chn) << 2; next_img = camseq_get_jpeg_wp(chn) << 2;
fvld = circbufValidPointer(next_img, &fp, chn); fvld = circbuf_valid_ptr(next_img, &fp, chn);
dev_dbg(g_dev_ptr, "LSEEK_CIRC_PREV: next_img = 0x%x, fvld = %d\n", next_img, fvld); dev_dbg(g_dev_ptr, "LSEEK_CIRC_PREV: next_img = 0x%x, fvld = %d\n", next_img, fvld);
dev_dbg(g_dev_ptr, "mem dump of last 0x40 bytes in buffer number %d\n", chn); dev_dbg(g_dev_ptr, "mem dump of last 0x40 bytes in buffer number %d\n", chn);
...@@ -500,7 +499,7 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { ...@@ -500,7 +499,7 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
// move file pointer only if previous frame valid // move file pointer only if previous frame valid
len32 = get_image_length(img_start, chn, NULL); len32 = get_image_length(img_start, chn, NULL);
if (circbufValidPointer(img_start, &fp, chn) < 0) if (circbuf_valid_ptr(img_start, &fp, chn) < 0)
return -EOVERFLOW; return -EOVERFLOW;
file->f_pos = img_start; file->f_pos = img_start;
break; break;
...@@ -516,23 +515,21 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { ...@@ -516,23 +515,21 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
case LSEEK_CIRC_FIRST: case LSEEK_CIRC_FIRST:
case LSEEK_CIRC_SCND: case LSEEK_CIRC_SCND:
{ {
int nf = 0; //! number of frames; int nf = 0; // number of frames;
int nz = 1; //! number of crossing of start of the circular buffer (counter to prevent looping forever) int nz = 1; // number of start crossing of the circular buffer (counter to prevent looping forever)
int prev_p, preprev_p; int prev_p, preprev_p;
//! Starting from the write pointer do be able to count all the frames in the buffer // starting from the write pointer to be able to count all the frames in the buffer
//rp=camSeqGetJPEG_wp();
rp = camseq_get_jpeg_wp(chn); rp = camseq_get_jpeg_wp(chn);
prev_p = preprev_p = rp; prev_p = preprev_p = rp;
file->f_pos = DW2BYTE(rp); file->f_pos = DW2BYTE(rp);
while (((fvld = circbufValidPointer(DW2BYTE(rp), &fp, chn)) >= 0) & (nz >= 0)) { while (((fvld = circbuf_valid_ptr(DW2BYTE(rp), &fp, chn)) >= 0) & (nz >= 0)) {
nf++; nf++;
preprev_p = prev_p; //! second known good (at least first one) preprev_p = prev_p; // second known good (at least first one)
prev_p=rp; //!now - current, known good prev_p=rp; // now - current, known good
//fl=ccam_dma_buf[X313_BUFFSUB(rp, 9)] ^ X313_LENGTH_MASK;
len32 = get_image_length(DW2BYTE(rp), chn, last_image_chunk); len32 = get_image_length(DW2BYTE(rp), chn, last_image_chunk);
dev_dbg(g_dev_ptr, "LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: number of frames = %d, rp = 0x%x, fvld = %d, len32 = 0x%x", nf, rp, fvld, len32); dev_dbg(g_dev_ptr, "LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: number of frames = %d, rp = 0x%x, fvld = %d, len32 = 0x%x", nf, rp, fvld, len32);
if ((len32 & MARKER_FF) != MARKER_FF ) break; //! no frames before rp (==prev_p) if ((len32 & MARKER_FF) != MARKER_FF ) break; //! no frames before rp (==prev_p)
//! move rp to the previous frame //! move rp to the previous frame
len32 &= 0xffffff; len32 &= 0xffffff;
inserted_bytes = ((CHUNK_SIZE - (((len32 % CHUNK_SIZE) + CCAM_MMAP_META) % CHUNK_SIZE) - ADJUSTMENT) % CHUNK_SIZE ) + ADJUSTMENT; inserted_bytes = ((CHUNK_SIZE - (((len32 % CHUNK_SIZE) + CCAM_MMAP_META) % CHUNK_SIZE) - ADJUSTMENT) % CHUNK_SIZE ) + ADJUSTMENT;
img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - inserted_bytes - CCAM_MMAP_META, len32); img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - inserted_bytes - CCAM_MMAP_META, len32);
...@@ -545,7 +542,6 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { ...@@ -545,7 +542,6 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
break; break;
} }
case LSEEK_CIRC_SETP: case LSEEK_CIRC_SETP:
//camSeqSetJPEG_rp(file->f_pos>>2);
dev_dbg(g_dev_ptr, "LSEK_CIRC_SETP: Setting jpeg_rp for channel %d to file->f_pos = 0x%x\n", chn, file->f_pos); dev_dbg(g_dev_ptr, "LSEK_CIRC_SETP: Setting jpeg_rp for channel %d to file->f_pos = 0x%x\n", chn, file->f_pos);
camseq_set_jpeg_rp(chn, file->f_pos >> 2); camseq_set_jpeg_rp(chn, file->f_pos >> 2);
break; break;
...@@ -555,46 +551,48 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { ...@@ -555,46 +551,48 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
break; break;
case LSEEK_CIRC_READY: case LSEEK_CIRC_READY:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_READY: checking fvld, fvld = %d\n", fvld); dev_dbg(g_dev_ptr, "LSEEK_CIRC_READY: checking fvld, fvld = %d\n", fvld);
if (fvld <=0) return -EINVAL; //! no frame is available better code? if (fvld <=0) return -EINVAL; // no frame is available better code?
break; break;
case LSEEK_CIRC_WAIT: case LSEEK_CIRC_WAIT:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_WAIT\n"); dev_dbg(g_dev_ptr, "LSEEK_CIRC_WAIT\n");
while (((fvld=circbufValidPointer(file->f_pos, &fp, chn)))==0) { //! only while not ready, ready or BAD - return while (((fvld=circbuf_valid_ptr(file->f_pos, &fp, chn)))==0) { // only while not ready, ready or BAD - return
//wait_event_interruptible(circbuf_wait_queue,(camSeqGetJPEG_wp()<<2)!=file->f_pos);
wait_event_interruptible(circbuf_wait_queue, (camseq_get_jpeg_wp(chn) << 2) != file->f_pos); wait_event_interruptible(circbuf_wait_queue, (camseq_get_jpeg_wp(chn) << 2) != file->f_pos);
} }
if (fvld < 0) return -ESPIPE; //!invalid seek - have better code? if (fvld < 0) return -ESPIPE; // invalid seek - have better code?
return file->f_pos ; //! data already available, return file pointer return file->f_pos ; // data already available, return file pointer
default: default:
if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) { if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) {
wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f))); wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
} }
} }
return ( file->f_pos ); //! file position >=0 return ( file->f_pos ); // file position >= 0
} }
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
// roll-over position // roll-over position
while (file->f_pos < 0) file->f_pos+=l; while (file->f_pos < 0) file->f_pos += CCAM_DMA_SIZE;
while (file->f_pos > l) file->f_pos-=l; while (file->f_pos > CCAM_DMA_SIZE) file->f_pos -= CCAM_DMA_SIZE;
if ((orig !=SEEK_END) && (file->f_pos == l)) file->f_pos=0; //!only for lseek (fd,0,SEEK_END) the result will be file size, others will roll to 0 if ((orig !=SEEK_END) && (file->f_pos == CCAM_DMA_SIZE)) file->f_pos=0; // only for lseek(fd,0,SEEK_END) the result will be file size, others will roll to 0
return file->f_pos ; return file->f_pos ;
} }
/** /**
* @brief This function handles write operations for circbuf file * @brief This function handles write operations for circbuf files.
* Note: never use \e file->f_pos in this function.
* @param[in] file pointer to <em>struct file</em> * @param[in] file pointer to <em>struct file</em>
* @param[in] buf pointer to buffer containing data * @param[in] buf pointer to buffer containing data
* @param[in] count number of bytes in buffer * @param[in] count number of bytes in buffer
* @param[in] off offset * @param[in] off offset
* @return number of bytes read form \e buf * @return number of bytes read form \e buf
*/ */
ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t *off) { ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t *off)
{
unsigned long p; unsigned long p;
char *char_pb = (char *)ccam_dma_buf; unsigned int minor = MINOR(file->f_inode->i_rdev);
struct circbuf_pd *priv = file->private_data; unsigned int chn = minor_to_chn(minor, NULL);
dev_dbg(g_dev_ptr, "minor = 0x%x, count = 0x%x, off = 0x%x", minor, count, off);
/* debug code follows*/ /* debug code follows*/
switch (buf[0] - 0x30) { switch (buf[0] - 0x30) {
...@@ -607,16 +605,13 @@ ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t ...@@ -607,16 +605,13 @@ ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t
} }
/* debug code end */ /* debug code end */
//D(printk("circbuf_write\n"));
/// ************* NOTE: Never use file->f_pos in write() and read() !!!
p = *off; p = *off;
if(p >= (CCAM_DMA_SIZE << 2)) if (p >= CCAM_DMA_SIZE)
p = (CCAM_DMA_SIZE << 2); p = CCAM_DMA_SIZE;
if((p + count) > (CCAM_DMA_SIZE << 2)) { // truncate count if ((p + count) > CCAM_DMA_SIZE)
count = (CCAM_DMA_SIZE << 2) - p; count = CCAM_DMA_SIZE - p;
} if (count) {
if(count) { if (copy_from_user(&circbuf_priv[chn].buf_ptr[BYTE2DW(p)], buf, count))
if(copy_from_user(&char_pb[p], buf, count))
return -EFAULT; return -EFAULT;
*off += count; *off += count;
} }
...@@ -624,27 +619,29 @@ ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t ...@@ -624,27 +619,29 @@ ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t
} }
/** /**
* @brief This function handles read operations for circbuf file * @brief This function handles read operations for circbuf files.
* Note: never use \e file->f_pos in this function.
* @param[in] file pointer to <em>struct file</em> * @param[in] file pointer to <em>struct file</em>
* @param[in] buf pointer to buffer where data will be written to * @param[in] buf pointer to buffer where data will be written to
* @param[in] count number of bytes written to \e buf * @param[in] count number of bytes written to \e buf
* @param[in] off offset * @param[in] off offset
* @return number of bytes written to \e buf * @return number of bytes written to \e buf
*/ */
ssize_t circbuf_read(struct file * file, char * buf, size_t count, loff_t *off) { ssize_t circbuf_read(struct file *file, char *buf, size_t count, loff_t *off)
{
unsigned long p; unsigned long p;
char * char_pb = (char *) ccam_dma_buf; unsigned int minor = MINOR(file->f_inode->i_rdev);
struct circbuf_pd *priv = file->private_data; unsigned int chn = minor_to_chn(minor, NULL);
dev_dbg(g_dev_ptr, "minor = 0x%x, count = 0x%x, off = 0x%x", minor, count, off);
p = *off; p = *off;
dev_dbg(g_dev_ptr, "read from circbuf pos = %d, count = %d, off = %d\n", p, count, off); if (p >= CCAM_DMA_SIZE)
if (p >= (CCAM_DMA_SIZE<<2)) p = (CCAM_DMA_SIZE<<2); p = CCAM_DMA_SIZE;
if( (p + count) > (CCAM_DMA_SIZE<<2)) { // truncate count if ((p + count) > CCAM_DMA_SIZE)
count = (CCAM_DMA_SIZE<<2) - p; count = CCAM_DMA_SIZE - p;
}
if (count) { if (count) {
if (copy_to_user(buf, &char_pb[p], count)) return -EFAULT; if (copy_to_user(buf, &circbuf_priv[chn].buf_ptr[BYTE2DW(p)], count))
// file->f_pos+=count; return -EFAULT;
*off+=count; *off+=count;
} }
return count; return count;
...@@ -653,7 +650,8 @@ ssize_t circbuf_read(struct file * file, char * buf, size_t count, loff_t *off) ...@@ -653,7 +650,8 @@ ssize_t circbuf_read(struct file * file, char * buf, size_t count, loff_t *off)
int circbuf_mmap(struct file *file, struct vm_area_struct *vma) int circbuf_mmap(struct file *file, struct vm_area_struct *vma)
{ {
int ret; int ret;
int chn = minor_to_chn(MINOR(file->f_inode->i_rdev)); unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
dev_dbg(g_dev_ptr, "vm_start = 0x%lx\n", vma->vm_start); dev_dbg(g_dev_ptr, "vm_start = 0x%lx\n", vma->vm_start);
dev_dbg(g_dev_ptr, "vm_end = 0x%lx\n", vma->vm_end); dev_dbg(g_dev_ptr, "vm_end = 0x%lx\n", vma->vm_end);
...@@ -661,10 +659,9 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -661,10 +659,9 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma)
dev_dbg(g_dev_ptr, "vm_file = 0x%lx\n", (unsigned long)vma->vm_file); dev_dbg(g_dev_ptr, "vm_file = 0x%lx\n", (unsigned long)vma->vm_file);
dev_dbg(g_dev_ptr, "ccam_dma_buf = 0x%lx\n", (unsigned long)circbuf_priv[chn].phys_addr); dev_dbg(g_dev_ptr, "ccam_dma_buf = 0x%lx\n", (unsigned long)circbuf_priv[chn].phys_addr);
/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ /* remap_pfn_range will mark the range VM_IO and VM_RESERVED */
ret = remap_pfn_range(vma, ret = remap_pfn_range(vma,
vma->vm_start, vma->vm_start,
//((unsigned long) virt_to_phys(&ccam_dma_buf[0])) >> PAGE_SHIFT, // Should be page-aligned
circbuf_priv[chn].phys_addr >> PAGE_SHIFT, circbuf_priv[chn].phys_addr >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_end - vma->vm_start,
vma->vm_page_prot); vma->vm_page_prot);
...@@ -674,34 +671,41 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -674,34 +671,41 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma)
return 0; return 0;
} }
/*!===========================================================================
*! If the current read pointer is invalid, circbuf_poll returns POLLHUP /**
*! as no data will be ever available until file poinetr is reset. * @brief This driver method is called when user-space program performs <em>poll, select</em> or
*! if it is valid, wait is setup and the blocking condition occurs * \e epoll system call.
*! ifthe current file pointer is equal to the FPGA write pointer *
*!===========================================================================*/ * If the current read pointer is invalid, circbuf_poll returns POLLHUP
* as no data will be ever available until file pointer is reset.
* If it is valid, wait is setup and blocking condition occurs in case
* current file pointer is equal to the FPGA write pointer.
* @param[in] file pointer to <em>struct file</em> structure
* @param[in] wait pointer to <em>struct poll_table</em> structure
* return POLLHUP if pointer is invalid, (POLLIN | POLLRDNORM) if frame is ready,
* 0 in case nothing is ready.
*/
unsigned int circbuf_poll (struct file *file, poll_table *wait) unsigned int circbuf_poll (struct file *file, poll_table *wait)
{ {
int w_ptr; int w_ptr;
unsigned int minor = MINOR(file->f_inode->i_rdev); unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor); unsigned int chn = minor_to_chn(minor, NULL);
struct interframe_params_t * fp; struct interframe_params_t * fp;
struct circbuf_pd * privData; int rslt;
privData = (struct circbuf_pd *) file->private_data;
int rslt; //!result of testing read poinetr
dev_dbg(g_dev_ptr, "minor = 0x%x\n", minor); dev_dbg(g_dev_ptr, "minor = 0x%x\n", minor);
rslt= circbufValidPointer(file->f_pos, &fp, chn);
if (rslt < 0) { //! not a valid read pointer, probable buffer overrun rslt = circbuf_valid_ptr(file->f_pos, &fp, chn);
if (rslt < 0) {
// not a valid read pointer, probable buffer overrun
dev_dbg(g_dev_ptr, "invalid pointer file->f_pos = 0x%x\n", file->f_pos); dev_dbg(g_dev_ptr, "invalid pointer file->f_pos = 0x%x\n", file->f_pos);
return POLLHUP ; return POLLHUP ;
} else if (rslt > 0) { } else if (rslt > 0) {
return POLLIN | POLLRDNORM; //! there was frame already available return POLLIN | POLLRDNORM; //! there was frame already available
} else { //! pointer valid, no frame yet } else {
// pointer valid, no frame yet
poll_wait(file, &circbuf_wait_queue, wait); poll_wait(file, &circbuf_wait_queue, wait);
//! Frame might become available during call to poll_wait so nobody will wake us up. // Frame might become available during call to poll_wait so nobody will wake us up,
//! Let's see if there is stillno frame // let's see if there is still no frame.
//if ((camSeqGetJPEG_wp()<<2)!=file->f_pos) return POLLIN | POLLRDNORM; //! we are lucky - got it
w_ptr = camseq_get_jpeg_wp(chn) << 2; w_ptr = camseq_get_jpeg_wp(chn) << 2;
if (w_ptr != file->f_pos) if (w_ptr != file->f_pos)
return POLLIN | POLLRDNORM; //! we are lucky - got it return POLLIN | POLLRDNORM; //! we are lucky - got it
......
...@@ -27,12 +27,23 @@ ...@@ -27,12 +27,23 @@
#define IMAGERAW_MINOR_FPN 2 #define IMAGERAW_MINOR_FPN 2
#define IMAGERAW_MINOR_UNLOCK 3 #define IMAGERAW_MINOR_UNLOCK 3
#define CIRCBUF_MINOR_CHN_OFFSET 30 #define CIRCBUF_MINOR 0x20
#define CIRCBUF_MINOR_CHN_0 30 #define CIRCBUF_MINOR_CHN_0 0x20
#define CIRCBUF_MINOR_CHN_1 31 #define CIRCBUF_MINOR_CHN_1 0x21
#define CIRCBUF_MINOR_CHN_2 32 #define CIRCBUF_MINOR_CHN_2 0x22
#define CIRCBUF_MINOR_CHN_3 33 #define CIRCBUF_MINOR_CHN_3 0x23
#define JPEGHEAD_MINOR 0x30
#define JPEGHEAD_MINOR_CHN_0 0x30
#define JPEGHEAD_MINOR_CHN_1 0x31
#define JPEGHEAD_MINOR_CHN_2 0x32
#define JPEGHEAD_MINOR_CHN_3 0x33
#define HUFFMAN_MINOR 0x40
#define HUFFMAN_MINOR_CHN_0 0x40
#define HUFFMAN_MINOR_CHN_1 0x41
#define HUFFMAN_MINOR_CHN_2 0x42
#define HUFFMAN_MINOR_CHN_3 0x43
#define CMOSCAM_MINOR_RWTABLES 9 #define CMOSCAM_MINOR_RWTABLES 9
#define CMOSCAM_MINOR_CIRCBUF 11 #define CMOSCAM_MINOR_CIRCBUF 11
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment