Commit 97ccb7c2 authored by Andrey Filippov's avatar Andrey Filippov

merged with master

parent fb527e25
...@@ -11,6 +11,7 @@ sysroots ...@@ -11,6 +11,7 @@ sysroots
.pydevproject .pydevproject
html html
*.directory *.directory
*.kate-swp
doxygen.tag doxygen.tag
# auto-generated files from x393 project # auto-generated files from x393 project
src/drivers/elphel/x393.c src/drivers/elphel/x393.c
...@@ -18,3 +19,6 @@ src/drivers/elphel/x393.h ...@@ -18,3 +19,6 @@ src/drivers/elphel/x393.h
src/drivers/elphel/x393_defs.h src/drivers/elphel/x393_defs.h
src/drivers/elphel/x393_map.h src/drivers/elphel/x393_map.h
src/drivers/elphel/x393_types.h src/drivers/elphel/x393_types.h
all_sources.lst
excluding.lst
attic
This source diff could not be displayed because it is too large. You can view the blob instead.
#!/usr/bin/env python
# encoding: utf-8
from __future__ import division
from __future__ import print_function
import sys
import os
import time
import xml.etree.ElementTree as ET
'''
TODO: make 2 runs, first before
bitbake linux-xlnx
khelper.py linux -1
#get timestamp
#next 2 commands - I do not understand why their access timestamp is set during previous command and does not change during bitbake
touch /home/eyesis/git/elphel393/linux-elphel/src/drivers/ata/ahci_elphel.c
touch /home/eyesis/git/elphel393/linux-elphel/src/drivers/elphel/sensor_common.c
bitbake linux-xlnx -c compile -f
khelper.py linux <timestamp_from_the_first_run>
'''
def file_tree(flist): # Each file in list is a file, no directories
ftree={}
for p in flist:
node = ftree
seg_list=p.split(os.sep)
last_i=len(seg_list)-1
for i,segm in enumerate(seg_list):
if not segm in node:
if i == last_i:
node[segm] = None
else:
node[segm] = {}
node=node[segm]
return ftree
def exclude_list(ftree, flist):
mark = "*" # no file/dir name can be "*"
def list_tree_recursive(root):
rslt = []
if not mark in root:
return [[""]] # convert to trailing "/" for directories
for n in root:
if not n == mark:
if root[n] is None:
rslt.append([n])
else:
for l in list_tree_recursive(root[n]):
rslt.append([n]+l)
return rslt
ftree[mark]=None # mark top level dir
for p in flist:
node = ftree
for segm in p.split(os.sep)[:-1]:
node=node[segm]
node[mark]=None # [mark] means used in flist
del node[p.split(os.sep)[-1]]
#print (ftree)
# for k in ftree:
# print(k)
#Now prune unused directories
#prune_recursive(ftree) # (assuming root is used)
# now create list
files_list_list = list_tree_recursive(ftree)
# print (files_list_list)
#converrt to file paths
pl = []
for l in files_list_list:
pl.append(os.path.join(*(l[1:])))
pl = sorted (pl)
return pl
def proc_tree():
DEBUG = True
extensions = [".h",".c",".cpp"]
exclude_start = ["linux"+os.sep+"scripts"+os.sep,"linux"+os.sep+"source"+os.sep+"scripts"+os.sep]
delta_t = 3 # seconds
try:
root_path = sys.argv[1]
except:
print ("Calling %s <root directory path> [timestamp]"%(os.path.basename(sys.argv[0])))
try:
start_time = float(sys.argv[2])
except:
start_time = 0.0
touch_files= start_time < 0.0
print ("root_path = %s"%(root_path))
# root_path = "/home/eyesis/git/poky/linux-elphel/linux/"
lstFiles = []
# Append files to a list
for path, _, files in os.walk(root_path, followlinks = True):
for f in files:
for ext in extensions:
if f.endswith(ext):
lstFiles.append(os.path.join(path, f))
break
all_tree= file_tree(sorted(lstFiles))
include_lst=[]
lst_a = []
latest_at=0
for p in lstFiles:
if touch_files:
if os.path.islink(p):
os.utime(os.path.realpath(p), None)
else:
os.utime(p, None)
else:
# at = time.ctime(os.stat(p).st_atime)
at = os.stat(p).st_atime
l = None
if os.path.islink(p):
l = os.path.realpath(p)
at = os.stat(l).st_atime
latest_at = max((latest_at,at))
if at > (start_time + delta_t):
#Scripts/lexers result in problems
exclude=False
for exStr in exclude_start:
if p.startswith(exStr):
exclude=True
break
if exclude:
break
#exclude_start
lst_a.append([p,at,l])
include_lst.append(p)
if touch_files:
print (len(lstFiles), "last time = ", time.time())
return
excluding = exclude_list(all_tree, include_lst)
# print (all_tree)
# print (sorted(include_lst))
# print ("|".join(excluding))
if DEBUG:
with open("all_sources.lst","w" ) as f:
for p in sorted(lstFiles):
at = os.stat(p).st_atime
lnk=""
if os.path.islink(p):
at = os.stat(os.path.realpath(p)).st_atime
lnk = os.path.realpath(p)
print (p,at,lnk, file=f)
with open("excluding.lst","w" ) as f:
for p in excluding:
print (p, file=f)
# include_tree= file_tree(sorted(include_lst))
# print(include_tree)
root_dir=include_lst[0].split(os.sep)[0]
print ("root_dir=",root_dir)
xml= ET.parse(".cproject")
root=xml.getroot()
# for child in root:
# print(child.tag, child.attrib)
for child in root.iter('sourceEntries'):
for gchild in child:
print(gchild.tag)
for child in root.iter('sourceEntries'):
for gchild in child:
if gchild.tag == 'entry':
attr = gchild.attrib
try:
if (attr['kind'] == 'sourcePath') and (attr['name'] == root_dir):
child.remove (gchild)
print ("Removed existing entry ",gchild.tag)
break
except:
print ("error matching attributes for ",gchild.tag)
pass
break #after first 'sourceEntries' - should be just one?
ET.SubElement(child, 'entry', {"flags":"VALUE_WORKSPACE_PATH", "kind":"sourcePath", "name":root_dir, "excluding":"|".join(excluding)})
for child in root.iter('sourceEntries'):
for gchild in child:
print(gchild.tag)
oneliner= ET.tostring(root)
#overwrites original .cproject, may change to somethong different
with open(".cproject", "wr") as f:
f.write("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?>""")
f.write(oneliner)
print (len(lstFiles), len(lst_a), "last access time = ",latest_at)
if __name__ == '__main__':
proc_tree()
\ No newline at end of file
...@@ -99,9 +99,9 @@ WARN_LOGFILE = ...@@ -99,9 +99,9 @@ WARN_LOGFILE =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the input files # Configuration options related to the input files
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
INPUT = linux/source/drivers/elphel linux/source/drivers/ata/ahci_elphel.c linux/source/drivers/clk/clk-si5338.c linux/source/drivers/misc/ltc3589.c linux/source/drivers/misc/vsc330x.c linux/source/drivers/mmc/host/sdhci.c linux/source/drivers/mmc/host/sdhci.h linux/source/drivers/mtd/nand/nand_base.c linux/source/drivers/mtd/nand/nand.h linux/source/drivers/mtd/nand/nandchip-micron.c linux/source/drivers/mtd/nand/pl35x_nand.c linux/source/include/elphel linux/source/include/linux/i2c/ltc3589.h INPUT = linux/source/drivers/elphel linux/source/drivers/ata/ahci_elphel.c linux/source/drivers/clk/clk-si5338.c linux/source/drivers/misc/ltc3589.c linux/source/drivers/misc/vsc330x.c linux/source/drivers/mmc/host/sdhci.c linux/source/drivers/mmc/host/sdhci.h linux/source/drivers/mtd/nand/nand_base.c linux/source/drivers/mtd/nand/nand.h linux/source/drivers/mtd/nand/nandchip-micron.c linux/source/drivers/mtd/nand/pl35x-nand.c linux/source/include/elphel linux/source/include/linux/i2c/ltc3589.h
INPUT_ENCODING = UTF-8 INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.h *.cpp *.c *.md FILE_PATTERNS = *.h *.c *.cpp *.md
RECURSIVE = YES RECURSIVE = YES
EXCLUDE = src/logos.cpp src/lodepng.cpp EXCLUDE = src/logos.cpp src/lodepng.cpp
EXCLUDE_SYMLINKS = NO EXCLUDE_SYMLINKS = NO
......
...@@ -17,7 +17,9 @@ obj-$(CONFIG_ELPHEL393) += clock10359.o ...@@ -17,7 +17,9 @@ obj-$(CONFIG_ELPHEL393) += clock10359.o
obj-$(CONFIG_ELPHEL393) += exif393.o obj-$(CONFIG_ELPHEL393) += exif393.o
obj-$(CONFIG_ELPHEL393) += x393_helpers.o obj-$(CONFIG_ELPHEL393) += x393_helpers.o
obj-$(CONFIG_ELPHEL393) += framepars.o obj-$(CONFIG_ELPHEL393) += framepars.o
#obj-$(CONFIG_ELPHEL393) += sensor_common.o x393.o obj-$(CONFIG_ELPHEL393) += sensor_common.o
#obj-$(CONFIG_ELPHEL393) += quantization_tables.o obj-$(CONFIG_ELPHEL393) += x393.o
#obj-$(CONFIG_ELPHEL393) += circbuf.o jpeghead.o obj-$(CONFIG_ELPHEL393) += quantization_tables.o
obj-$(CONFIG_ELPHEL393) += circbuf.o
obj-$(CONFIG_ELPHEL393) += jpeghead.o
...@@ -6,24 +6,20 @@ ...@@ -6,24 +6,20 @@
* *
* @copyright Copyright (C) 2016 Elphel, Inc * @copyright Copyright (C) 2016 Elphel, Inc
* *
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//#define DEBUG 1
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -31,65 +27,44 @@ ...@@ -31,65 +27,44 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/fs.h> #include <linux/fs.h>
//#include <linux/string.h>
#include <linux/init.h> #include <linux/init.h>
//#include <linux/time.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
//#include <asm/system.h>
//#include <asm/arch/memmap.h>
//#include <asm/svinto.h> obsolete
//#include <asm/io.h>
/*#include <asm/arch/dma.h>
#include <asm/arch/hwregs/dma_defs.h>
#include <asm/arch/hwregs/dma.h>
#include <asm/arch/hwregs/reg_map.h>
#include <asm/arch/hwregs/bif_dma_defs.h>
*/
//#include <asm/irq.h>
//#include <asm/atomic.h>
//#include <asm/delay.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <elphel/driver_numbers.h> #include <elphel/driver_numbers.h>
#include <elphel/c313a.h> #include <elphel/c313a.h>
#include <elphel/elphel393-mem.h> #include <elphel/elphel393-mem.h>
#include "framepars.h" // just for ELPHEL_DEBUG bit mask #include "framepars.h"
#include "sensor_common.h" #include "sensor_common.h"
#include "jpeghead.h" #include "jpeghead.h"
#include "circbuf.h" #include "circbuf.h"
#include "exif.h" #include "exif.h"
#include "x393_macro.h" #include "x393_macro.h"
//#include "x393.h"
#include "x393_helpers.h" #include "x393_helpers.h"
/** @brief Driver name displayed in system logs */
#define CIRCBUF_DRIVER_NAME "circbuf driver" #define CIRCBUF_DRIVER_NAME "circbuf driver"
/** Wait queue for the processes waiting for a new frame to appear in the circular buffer */ /** @brief Wait queue for the processes waiting for a new frame to appear in the circular buffer */
wait_queue_head_t circbuf_wait_queue; wait_queue_head_t circbuf_wait_queue;
struct circbuf_priv_t circbuf_priv[SENSOR_PORTS]; struct circbuf_priv_t circbuf_priv[SENSOR_PORTS];
struct circbuf_priv_t *circbuf_priv_ptr = circbuf_priv; struct circbuf_priv_t *circbuf_priv_ptr = circbuf_priv;
/** @brief Global pointer to basic device structure. This pointer is used in debugfs output functions */
static struct device *g_dev_ptr; static struct device *g_dev_ptr;
/** @brief Structure used for matching a device from device tree */
static const struct of_device_id elphel393_circbuf_of_match[]; static const struct of_device_id elphel393_circbuf_of_match[];
unsigned long *ccam_dma_buf_ptr[SENSOR_PORTS] = {NULL}; unsigned long *ccam_dma_buf_ptr[SENSOR_PORTS] = {NULL};
/* debug code */ /**
//extern long long zero_counter[IMAGE_CHN_NUM]; * @brief Set up pointers to memory where circular buffers are located. The memory
/* end of debug code*/ * for circular buffers is reserved using CMA mechanism.
* @param[in] pdev driver's platform device structure
* @return 0 if pointers were set up and negative error code otherwise
*/
int init_ccam_dma_buf_ptr(struct platform_device *pdev) int init_ccam_dma_buf_ptr(struct platform_device *pdev)
{ {
int i; int i;
...@@ -124,6 +99,13 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev) ...@@ -124,6 +99,13 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
return 0; return 0;
} }
/**
* @brief Process circular buffer file opening and define further action in accordance
* with minor file number.
* @param[in] inode
* @param[in] filp
* @return 0 if file was opened successfully and negative error code otherwise
*/
int circbuf_all_open(struct inode *inode, struct file *filp) int circbuf_all_open(struct inode *inode, struct file *filp)
{ {
int res; int res;
...@@ -148,6 +130,13 @@ int circbuf_all_open(struct inode *inode, struct file *filp) ...@@ -148,6 +130,13 @@ int circbuf_all_open(struct inode *inode, struct file *filp)
return res; return res;
} }
/**
* @brief Process circular buffer file closing and define further action in accordance
* with minor file number.
* @param[in] inode
* @param[in] filp
* @return 0 if file was opened successfully and negative error code otherwise
*/
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;
...@@ -173,6 +162,14 @@ int circbuf_all_release(struct inode *inode, struct file *filp) ...@@ -173,6 +162,14 @@ int circbuf_all_release(struct inode *inode, struct file *filp)
return res; return res;
} }
/**
* @brief Process lseek operation on circular buffer file and define further
* action in accordance with minor file number.
* @param[in] file pointer to file structure corresponding to the circular buffer file
* @param[in] offset offset in bytes
* @param[in] orig where the @e offset should start
* @return The resulting offset location in bytes from the beginning of the file.
*/
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)
{ {
int rp; int rp;
...@@ -198,6 +195,15 @@ loff_t circbuf_all_lseek(struct file *file, loff_t offset, int orig) ...@@ -198,6 +195,15 @@ loff_t circbuf_all_lseek(struct file *file, loff_t offset, int orig)
} }
} }
/**
* @brief Process read operation on circular buffer file and define further
* action in accordance with minor file number.
* @param[in] file pointer to file structure corresponding to the circular buffer file
* @param[out] buf pointer to user buffer where the data should be placed
* @param[in] count the size of requested data transfer
* @param[in] off file position the user is accessing
* @return The number of bytes copied or negative error code.
*/
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)
{ {
unsigned int minor = MINOR(file->f_inode->i_rdev); unsigned int minor = MINOR(file->f_inode->i_rdev);
...@@ -217,6 +223,15 @@ ssize_t circbuf_all_read(struct file *file, char *buf, size_t count, loff_t *off ...@@ -217,6 +223,15 @@ ssize_t circbuf_all_read(struct file *file, char *buf, size_t count, loff_t *off
} }
} }
/**
* @brief Process write operation on circular buffer file and define further
* action in accordance with minor file number.
* @param[in] file pointer to file structure corresponding to the circular buffer file
* @param[out] buf pointer to user buffer holding the data
* @param[in] count the size of requested data transfer
* @param[in] off file position the user is accessing
* @return The number of bytes copied or negative error code.
*/
ssize_t circbuf_all_write(struct file *file, const char *buf, size_t count, loff_t *off) ssize_t circbuf_all_write(struct file *file, const char *buf, size_t count, loff_t *off)
{ {
unsigned int minor = MINOR(file->f_inode->i_rdev); unsigned int minor = MINOR(file->f_inode->i_rdev);
...@@ -237,6 +252,14 @@ ssize_t circbuf_all_write(struct file *file, const char *buf, size_t count, loff ...@@ -237,6 +252,14 @@ ssize_t circbuf_all_write(struct file *file, const char *buf, size_t count, loff
} }
} }
/**
* @brief Process memory map operation on circular buffer file and define further
* action in accordance with minor file number. Only circular buffer itself supports
* memory mapped operation, all other files will return an error.
* @param[in] file pointer to file structure corresponding to the circular buffer file
* @param[in] vma contains the information about the virtual address range
* @return 0 if file was mapped successfully and negative error code otherwise
*/
int circbuf_all_mmap(struct file *file, struct vm_area_struct *vma) int circbuf_all_mmap(struct file *file, struct vm_area_struct *vma)
{ {
unsigned int minor = MINOR(file->f_inode->i_rdev); unsigned int minor = MINOR(file->f_inode->i_rdev);
...@@ -252,7 +275,16 @@ int circbuf_all_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -252,7 +275,16 @@ int circbuf_all_mmap(struct file *file, struct vm_area_struct *vma)
} }
} }
unsigned int circbuf_all_poll (struct file *file, poll_table *wait) /**
* @brief Process poll operation on circular buffer file and define further
* action in accordance with minor file number. Only circular buffer itself supports
* memory mapped operation, all other files will return an error.
* @param[in] file pointer to file structure corresponding to the circular buffer file
* @param[in] wait pointer to a wait queue
* @return POLLHUP if pointer is invalid, (POLLIN | POLLRDNORM) if frame is ready,
* 0 in case nothing is ready or incorrect minor number received.
*/
unsigned int circbuf_all_poll(struct file *file, poll_table *wait)
{ {
unsigned int minor = MINOR(file->f_inode->i_rdev); unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int dev_type; unsigned int dev_type;
...@@ -263,10 +295,16 @@ unsigned int circbuf_all_poll (struct file *file, poll_table *wait) ...@@ -263,10 +295,16 @@ unsigned int circbuf_all_poll (struct file *file, poll_table *wait)
case CIRCBUF_MINOR: case CIRCBUF_MINOR:
return circbuf_poll(file, wait); return circbuf_poll(file, wait);
default: default:
return -EINVAL; return 0;
} }
} }
/**
* @brief Process circular buffer file opening.
* @param[in] inode
* @param[in] filp
* @return Always 0.
*/
int circbuf_open(struct inode *inode, struct file *filp) int circbuf_open(struct inode *inode, struct file *filp)
{ {
inode->i_size = CCAM_DMA_SIZE; inode->i_size = CCAM_DMA_SIZE;
...@@ -275,6 +313,13 @@ int circbuf_open(struct inode *inode, struct file *filp) ...@@ -275,6 +313,13 @@ int circbuf_open(struct inode *inode, struct file *filp)
return 0; return 0;
} }
/**
* @brief Debug function, prints the content of interframe parameters.
* @param[in] params pointer to #interframe_params_t which should be printed
* @param[in] offset offset in circular buffer where the @e params is located
* @param[in] chn channel number this @e params belongs to
* @return None
*/
void dump_interframe_params(struct interframe_params_t *params, int offset, unsigned int chn) void dump_interframe_params(struct interframe_params_t *params, int offset, unsigned int chn)
{ {
dev_dbg(g_dev_ptr, "Dump of interframe parameters at offset 0x%x [chn %u]:\n", offset, chn); dev_dbg(g_dev_ptr, "Dump of interframe parameters at offset 0x%x [chn %u]:\n", offset, chn);
...@@ -282,7 +327,13 @@ void dump_interframe_params(struct interframe_params_t *params, int offset, unsi ...@@ -282,7 +327,13 @@ void dump_interframe_params(struct interframe_params_t *params, int offset, unsi
} }
/** /**
* @brief Get the length of an image before given pointer * @brief Get the length of an image before given pointer. The pointer @e byte_offset
* points to the beginning of new image data segment and this function calculates
* the length of the previous image data segment and returns a pointer to the end of
* this segment.
* @param[in] byte_offset the offset of image data in circular buffer
* @param[in] chn circular buffer channel
* @param[out] last_chunk_offset the offset where image data ends
*/ */
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)
{ {
...@@ -297,7 +348,6 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun ...@@ -297,7 +348,6 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun
if ((len32 & MARKER_FF) != MARKER_FF) { if ((len32 & MARKER_FF) != MARKER_FF) {
dev_dbg(g_dev_ptr, "[chn %u] failed to get 0xff marker at offset 0x%x\n", chn, offset); dev_dbg(g_dev_ptr, "[chn %u] failed to get 0xff marker at offset 0x%x\n", chn, offset);
// byte_offset = X393_BUFFSUB(byte_offset, CHUNK_SIZE);
last_image_chunk = X393_BUFFSUB(byte_offset, OFFSET_X40 + CHUNK_SIZE); last_image_chunk = X393_BUFFSUB(byte_offset, OFFSET_X40 + CHUNK_SIZE);
offset = X393_BUFFADD(last_image_chunk, CHUNK_SIZE - CCAM_MMAP_META_LENGTH); offset = X393_BUFFADD(last_image_chunk, CHUNK_SIZE - CCAM_MMAP_META_LENGTH);
len32 = circbuf_priv[chn].buf_ptr[BYTE2DW(offset)]; len32 = circbuf_priv[chn].buf_ptr[BYTE2DW(offset)];
...@@ -317,9 +367,9 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun ...@@ -317,9 +367,9 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun
/** /**
* @brief Check that read pointer is valid * @brief Check that read pointer is valid
* @param[in] rp read pointer to be checked; this pointer is in bytes * @param[in] rp_offset 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 * @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 * frame header before @e rp and will point to its parameters
* @param[in] chn specify compressor channel number which pointer should be checked * @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, * @return 0 if the pointer is for the frame yet to be acquired, 1 if there is a valid frame at this address,
* 2 if file pointer should be advanced by 32 bytes, * 2 if file pointer should be advanced by 32 bytes,
...@@ -372,60 +422,13 @@ int circbuf_valid_ptr(loff_t *rp_offset, struct interframe_params_t **fpp, unsig ...@@ -372,60 +422,13 @@ int circbuf_valid_ptr(loff_t *rp_offset, struct interframe_params_t **fpp, unsig
* @brief Get image start offset pointed by its last data chunk * @brief Get image start offset pointed by its last data chunk
* @param[in] last_chunk_offset offset of the last image data chunk * @param[in] last_chunk_offset offset of the last image data chunk
* @param[in] len32 length of image * @param[in] len32 length of image
* @return image start offset * @return Image start offset
*/ */
inline int get_image_start(int last_chunk_offset, unsigned int len32) inline int get_image_start(int last_chunk_offset, unsigned int len32)
{ {
return X393_BUFFSUB(last_chunk_offset + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32); return X393_BUFFSUB(last_chunk_offset + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, 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
* The following command is used for profiling from user space applications. It does not change file pointer:
* LSEEK_CIRC_UTIME return current value of microsecond counter.
* @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
*/
/* debug code follows */ /* debug code follows */
void stop_compressor(unsigned int chn) void stop_compressor(unsigned int chn)
{ {
...@@ -482,6 +485,45 @@ void dump_state(unsigned int chn) ...@@ -482,6 +485,45 @@ void dump_state(unsigned int chn)
printk(KERN_DEBUG "=== end of state dump, %d frame(s) analyzed ===\n", nf); printk(KERN_DEBUG "=== end of state dump, %d frame(s) analyzed ===\n", nf);
} }
/* end of debug code */ /* end of debug code */
/**
* @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:
* command | description
* ------------------|------------------------------------------------------------------------------------
* 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):
* command | description
* ------------------|------------------------------------------------------------------------------------
* 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
* The following command is used for profiling from user space applications. It does not change file pointer:
* LSEEK_CIRC_UTIME return current value of microsecond counter.
* @param[in] file pointer to @e file structure
* @param[in] offset offset inside buffer in bytes
* @param[in] orig where the @e offset should start
* @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) loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
{ {
unsigned int len32 = 0; unsigned int len32 = 0;
...@@ -500,7 +542,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -500,7 +542,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
break; break;
case SEEK_CUR: case SEEK_CUR:
if (offset) file->f_pos += offset; if (offset) file->f_pos += offset;
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 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) {
...@@ -536,11 +578,11 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -536,11 +578,11 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
case LSEEK_CIRC_FREE: case LSEEK_CIRC_FREE:
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FREE: checking remaining memory in circbuf\n", chn); dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FREE: checking remaining memory in circbuf\n", chn);
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 + CCAM_DMA_SIZE)); //!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, "[chn %u] LSEEK_CIRC_USED: checking used memory in circbuf\n", chn); dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_USED: checking used memory in circbuf\n", chn);
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 + CCAM_DMA_SIZE)); //!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;
...@@ -598,7 +640,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -598,7 +640,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_NEXT: file->f_pos = 0x%llx, fvld = %d, fp->len32 = 0x%lx\n", chn, dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_NEXT: file->f_pos = 0x%llx, fvld = %d, fp->len32 = 0x%lx\n", chn,
file->f_pos, fvld, fp->frame_length); file->f_pos, fvld, fp->frame_length);
if (fvld <= 0) { if (fvld <= 0) {
return -EOVERFLOW; //! no frames after current return -EOVERFLOW; // no frames after current
} else if (fvld == 2) { } else if (fvld == 2) {
//file->f_pos += CHUNK_SIZE; //file->f_pos += CHUNK_SIZE;
dev_dbg(g_dev_ptr, "[chn %u] read pointer file->f_pos was advanced by 0x20 bytes\n", chn); dev_dbg(g_dev_ptr, "[chn %u] read pointer file->f_pos was advanced by 0x20 bytes\n", chn);
...@@ -627,8 +669,8 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -627,8 +669,8 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
len32 = get_image_length(rp_b, chn, &last_image_chunk); len32 = get_image_length(rp_b, chn, &last_image_chunk);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: number of frames = %d, rp_b = 0x%x, fvld = %d, len32 = 0x%x", chn, dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: number of frames = %d, rp_b = 0x%x, fvld = %d, len32 = 0x%x", chn,
nf, rp_b, fvld, len32); nf, rp_b, 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 &= FRAME_LENGTH_MASK; len32 &= FRAME_LENGTH_MASK;
//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);
img_start = get_image_start(last_image_chunk, len32); img_start = get_image_start(last_image_chunk, len32);
...@@ -684,19 +726,19 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -684,19 +726,19 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
return file->f_pos ; return file->f_pos ;
} }
unsigned short circbuf_quality = 100;
unsigned short circbuf_height = 1936;
unsigned short circbuf_width = 2592;
unsigned char circbuf_byrshift = 3;
/** /**
* @brief This function handles write operations for circbuf files. * @brief This function handles write operations for circbuf files.
* Note: never use \e file->f_pos in this function. * @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
*/ */
unsigned short circbuf_quality = 100;
unsigned short circbuf_height = 1936;
unsigned short circbuf_width = 2592;
unsigned char circbuf_byrshift = 3;
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;
...@@ -794,12 +836,12 @@ ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t * ...@@ -794,12 +836,12 @@ ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t *
/** /**
* @brief This function handles read operations for circbuf files. * @brief This function handles read operations for circbuf files.
* Note: never use \e file->f_pos in this function. * @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)
{ {
...@@ -821,6 +863,12 @@ ssize_t circbuf_read(struct file *file, char *buf, size_t count, loff_t *off) ...@@ -821,6 +863,12 @@ ssize_t circbuf_read(struct file *file, char *buf, size_t count, loff_t *off)
return count; return count;
} }
/**
* @brief Process memory map operation on circular buffer file.
* @param[in] file pointer to file structure corresponding to the circular buffer file
* @param[in] vma contains the information about the virtual address range
* @return 0 if file was mapped successfully and negative error code otherwise
*/
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;
...@@ -840,17 +888,6 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -840,17 +888,6 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_end - vma->vm_start, vma->vm_end - vma->vm_start,
vma->vm_page_prot); vma->vm_page_prot);
// ret = dma_common_mmap(g_dev_ptr, vma,
// circbuf_priv[chn].buf_ptr,
// circbuf_priv[chn].phys_addr,
// pElphel_buf->size * PAGE_SIZE);
//
// ret = arm_dma_mmap(g_dev_ptr, vma,
// circbuf_priv[chn].buf_ptr,
// circbuf_priv[chn].phys_addr,
// pElphel_buf->size * PAGE_SIZE,
// NULL);
dev_dbg(g_dev_ptr, "remap_pfn_range returned 0x%x\n", ret); dev_dbg(g_dev_ptr, "remap_pfn_range returned 0x%x\n", ret);
if (ret) return -EAGAIN; if (ret) return -EAGAIN;
...@@ -859,7 +896,7 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -859,7 +896,7 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma)
/** /**
* @brief This driver method is called when user-space program performs <em>poll, select</em> or * @brief This driver method is called when user-space program performs <em>poll, select</em> or
* \e epoll system call. * @e epoll system call.
* *
* If the current read pointer is invalid, circbuf_poll returns POLLHUP * If the current read pointer is invalid, circbuf_poll returns POLLHUP
* as no data will be ever available until file pointer is reset. * as no data will be ever available until file pointer is reset.
...@@ -867,7 +904,7 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -867,7 +904,7 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma)
* current file pointer is equal to the FPGA write pointer. * current file pointer is equal to the FPGA write pointer.
* @param[in] file pointer to <em>struct file</em> structure * @param[in] file pointer to <em>struct file</em> structure
* @param[in] wait pointer to <em>struct poll_table</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, * @return POLLHUP if pointer is invalid, (POLLIN | POLLRDNORM) if frame is ready,
* 0 in case nothing 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)
...@@ -885,7 +922,7 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait) ...@@ -885,7 +922,7 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait)
dev_dbg(g_dev_ptr, "invalid pointer file->f_pos = 0x%llx\n", file->f_pos); dev_dbg(g_dev_ptr, "invalid pointer file->f_pos = 0x%llx\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 { } else {
// pointer valid, no frame yet // pointer valid, no frame yet
poll_wait(file, &circbuf_wait_queue, wait); poll_wait(file, &circbuf_wait_queue, wait);
...@@ -893,7 +930,7 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait) ...@@ -893,7 +930,7 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait)
// let's see if there is still no frame. // let's see if there is still no frame.
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
} }
return 0; // nothing ready return 0; // nothing ready
} }
...@@ -903,7 +940,6 @@ static struct file_operations circbuf_fops = { ...@@ -903,7 +940,6 @@ static struct file_operations circbuf_fops = {
.llseek = circbuf_all_lseek, .llseek = circbuf_all_lseek,
.read = circbuf_all_read, .read = circbuf_all_read,
.write = circbuf_all_write, .write = circbuf_all_write,
//ioctl: circbuf_all_ioctl,
.open = circbuf_all_open, .open = circbuf_all_open,
.mmap = circbuf_all_mmap, .mmap = circbuf_all_mmap,
.poll = circbuf_all_poll, .poll = circbuf_all_poll,
...@@ -912,7 +948,7 @@ static struct file_operations circbuf_fops = { ...@@ -912,7 +948,7 @@ static struct file_operations circbuf_fops = {
/** /**
* @brief cirbuf driver probing function * @brief cirbuf driver probing function
* @param[in] pdev pointer to \b platform_device structure * @param[in] pdev pointer to @e platform_device structure
* @return 0 on success or negative error code otherwise * @return 0 on success or negative error code otherwise
*/ */
static int circbuf_all_init(struct platform_device *pdev) static int circbuf_all_init(struct platform_device *pdev)
...@@ -959,6 +995,11 @@ static int circbuf_all_init(struct platform_device *pdev) ...@@ -959,6 +995,11 @@ static int circbuf_all_init(struct platform_device *pdev)
return 0; return 0;
} }
/**
* @brief cirbuf driver remove function
* @param[in] pdev pointer to @e platform_device structure
* @return Always 0.
*/
static int circbuf_remove(struct platform_device *pdev) static int circbuf_remove(struct platform_device *pdev)
{ {
unregister_chrdev(CIRCBUF_MAJOR, "circbuf_operations"); unregister_chrdev(CIRCBUF_MAJOR, "circbuf_operations");
......
// FILE NAME : cxsdma.h /** @file circbuf.h
// read/write image and FPN buffers from SDRAM *
* @brief Drivers to manipulate large circular buffer that holds compressed
* images/video. Buffer frame data is filled in by the FPGA, frame pointers and
* essential frames metadata filled during servicing of the interrupts.
*
* @copyright Copyright (C) 2016 Elphel, Inc
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CIRCBUF_H #ifndef _CIRCBUF_H
#define _CIRCBUF_H #define _CIRCBUF_H
#include <linux/poll.h> #include <linux/poll.h>
int circbuf_all_open (struct inode *inode, struct file *filp); // set filesize /** @brief Circular buffer private data */
struct circbuf_priv_t {
int minor; ///< device file minor number
unsigned long *buf_ptr; ///< pointer to circular buffer memory region
dma_addr_t phys_addr; ///< physical address of memory region reported by memory driver
};
extern struct circbuf_priv_t *circbuf_priv_ptr;
extern wait_queue_head_t circbuf_wait_queue;
int circbuf_all_open (struct inode *inode, struct file *filp); // set file size
int circbuf_all_release(struct inode *inode, struct file *filp); int circbuf_all_release(struct inode *inode, struct file *filp);
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);
ssize_t circbuf_all_write (struct file * file, const char * buf, size_t count, loff_t *off); ssize_t circbuf_all_write (struct file * file, const char * buf, size_t count, loff_t *off);
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);
int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma); int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma);
unsigned int circbuf_all_poll (struct file *file, poll_table *wait); unsigned int circbuf_all_poll (struct file *file, poll_table *wait);
//!just to notify it is not implemented
int circbuf_all_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
int circbuf_open (struct inode *inode, struct file *filp); // set file size
int circbuf_open (struct inode *inode, struct file *filp); // set filesize
loff_t circbuf_lseek (struct file * file, loff_t offset, int orig); loff_t circbuf_lseek (struct file * file, loff_t offset, int orig);
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);
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);
int circbuf_mmap (struct file *file, struct vm_area_struct *vma); int circbuf_mmap (struct file *file, struct vm_area_struct *vma);
unsigned int circbuf_poll (struct file *file, poll_table *wait); unsigned int circbuf_poll (struct file *file, poll_table *wait);
#ifdef USE_OLD_CODE
//int init_ccam_dma_buf_ptr(void); //int init_ccam_dma_buf_ptr(void);
/*!====================================================================================== /*!======================================================================================
* Wait queue for the processes waiting for a new frame to appear in the circular buffer * Wait queue for the processes waiting for a new frame to appear in the circular buffer
*======================================================================================*/ *======================================================================================*/
extern wait_queue_head_t circbuf_wait_queue; extern wait_queue_head_t circbuf_wait_queue;
// private data // private data
struct circbuf_priv_t { struct circbuf_priv_t {
int minor; int minor;
...@@ -38,6 +61,7 @@ struct circbuf_priv_t { ...@@ -38,6 +61,7 @@ struct circbuf_priv_t {
dma_addr_t phys_addr; dma_addr_t phys_addr;
}; };
extern struct circbuf_priv_t *circbuf_priv_ptr; extern struct circbuf_priv_t *circbuf_priv_ptr;
#endif
/* debug code follows */ /* debug code follows */
extern unsigned short circbuf_quality; extern unsigned short circbuf_quality;
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <asm/outercache.h> #include <asm/outercache.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <elphel/elphel393-mem.h> #include <elphel/elphel393-mem.h>
#include "x393_helpers.h"
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */ #define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444 #define SYSFS_READONLY 0444
...@@ -207,18 +206,6 @@ static ssize_t get_size_bidir(struct device *dev, struct device_attribute *attr, ...@@ -207,18 +206,6 @@ static ssize_t get_size_bidir(struct device *dev, struct device_attribute *attr,
return sprintf(buf,"%u\n", _elphel_buf.bidir_size); return sprintf(buf,"%u\n", _elphel_buf.bidir_size);
} }
/*
static ssize_t get_cache(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Write into this file to flush L1/L2 caches to memory.\n");
}
static ssize_t flush_cache(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
__cpuc_flush_kern_all();
outer_flush_all();
return count;
}
*/
static ssize_t sync_for_cpu_h2d(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t sync_for_cpu_h2d(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
dma_addr_t paddr; dma_addr_t paddr;
...@@ -313,47 +300,6 @@ static ssize_t sync_for_device_bidir(struct device *dev, struct device_attribute ...@@ -313,47 +300,6 @@ static ssize_t sync_for_device_bidir(struct device *dev, struct device_attribute
return count; return count;
} }
static ssize_t flush_cpu_cache(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
const int buff_size = 0x1000000;
const int buff_start_offset = 0x100000;
unsigned int chn;
int start_offset, end_offset;
int num_items;
dma_addr_t phys_addr_start, phys_addr_end;
u32 start_time, end_time;
num_items = sscanf(buf, "%u:%d:%d", &chn, &start_offset, &end_offset);
start_time = get_rtc_usec();
if (num_items == 3) {
// invalidate L2 caches
if (end_offset > start_offset) {
// handle single buffer case
phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size + start_offset;
phys_addr_end = _elphel_buf.paddr + buff_start_offset + chn * buff_size + end_offset - 1;
outer_inv_range(phys_addr_start, phys_addr_end);
} else {
// handle split buffer case when pointer rolls over the end
// first, process the peace at the end of the buffer
phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size + start_offset;
phys_addr_end = _elphel_buf.paddr + buff_start_offset + ++chn * buff_size - 1;
outer_inv_range(phys_addr_start, phys_addr_end);
// second, process the peace at the start of the buffer
phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size;
phys_addr_end = _elphel_buf.paddr + buff_start_offset + chn * buff_size + end_offset - 1;
outer_inv_range(phys_addr_start, phys_addr_end);
}
}
end_time = get_rtc_usec();
if (start_time == 0 && end_time == 0) {
pr_info("Unable to get usec values\n");
} else {
pr_info("Cache invalidate time: %lu\n", end_time - start_time);
}
return count;
}
static ssize_t get_sync_for_device_h2d(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_sync_for_device_h2d(struct device *dev, struct device_attribute *attr, char *buf)
{ {
return sprintf(buf,"Write address/length pair into this file to hand this region of the host to device DMA buffer to device (after CPU writes).\n"); return sprintf(buf,"Write address/length pair into this file to hand this region of the host to device DMA buffer to device (after CPU writes).\n");
...@@ -378,11 +324,6 @@ static ssize_t get_sync_for_cpu_bidir(struct device *dev, struct device_attribut ...@@ -378,11 +324,6 @@ static ssize_t get_sync_for_cpu_bidir(struct device *dev, struct device_attribut
{ {
return sprintf(buf,"Write address/length pair into this file to hand this region of the bidirectional DMA buffer to CPU (before CPU reads).\n"); return sprintf(buf,"Write address/length pair into this file to hand this region of the bidirectional DMA buffer to CPU (before CPU reads).\n");
} }
static ssize_t get_flush_cpu_cache(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "Write command and address into this file to flush CPU caches. Format 'chn:start_offset:end_offset' where "
"'chn' is sensor channel, 'start_offset' and 'end_offset' are start and end data offsets in circbuf\n");
}
static DEVICE_ATTR(buffer_address, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr, NULL); static DEVICE_ATTR(buffer_address, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr, NULL);
static DEVICE_ATTR(buffer_pages, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size, NULL); static DEVICE_ATTR(buffer_pages, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size, NULL);
...@@ -392,14 +333,12 @@ static DEVICE_ATTR(buffer_address_d2h, SYSFS_PERMISSIONS & SYSFS_READONLY, ...@@ -392,14 +333,12 @@ static DEVICE_ATTR(buffer_address_d2h, SYSFS_PERMISSIONS & SYSFS_READONLY,
static DEVICE_ATTR(buffer_pages_d2h, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size_d2h, NULL); static DEVICE_ATTR(buffer_pages_d2h, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size_d2h, NULL);
static DEVICE_ATTR(buffer_address_bidir, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr_bidir, NULL); static DEVICE_ATTR(buffer_address_bidir, SYSFS_PERMISSIONS & SYSFS_READONLY, get_paddr_bidir, NULL);
static DEVICE_ATTR(buffer_pages_bidir, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size_bidir, NULL); static DEVICE_ATTR(buffer_pages_bidir, SYSFS_PERMISSIONS & SYSFS_READONLY, get_size_bidir, NULL);
//static DEVICE_ATTR(buffer_flush, SYSFS_PERMISSIONS, get_cache, flush_cache);
static DEVICE_ATTR(sync_for_cpu_h2d, SYSFS_PERMISSIONS, get_sync_for_cpu_h2d, sync_for_cpu_h2d); static DEVICE_ATTR(sync_for_cpu_h2d, SYSFS_PERMISSIONS, get_sync_for_cpu_h2d, sync_for_cpu_h2d);
static DEVICE_ATTR(sync_for_device_h2d, SYSFS_PERMISSIONS, get_sync_for_device_h2d, sync_for_device_h2d); static DEVICE_ATTR(sync_for_device_h2d, SYSFS_PERMISSIONS, get_sync_for_device_h2d, sync_for_device_h2d);
static DEVICE_ATTR(sync_for_cpu_d2h, SYSFS_PERMISSIONS, get_sync_for_cpu_d2h, sync_for_cpu_d2h); static DEVICE_ATTR(sync_for_cpu_d2h, SYSFS_PERMISSIONS, get_sync_for_cpu_d2h, sync_for_cpu_d2h);
static DEVICE_ATTR(sync_for_device_d2h, SYSFS_PERMISSIONS, get_sync_for_device_d2h, sync_for_device_d2h); static DEVICE_ATTR(sync_for_device_d2h, SYSFS_PERMISSIONS, get_sync_for_device_d2h, sync_for_device_d2h);
static DEVICE_ATTR(sync_for_cpu_bidir, SYSFS_PERMISSIONS, get_sync_for_cpu_bidir, sync_for_cpu_bidir); static DEVICE_ATTR(sync_for_cpu_bidir, SYSFS_PERMISSIONS, get_sync_for_cpu_bidir, sync_for_cpu_bidir);
static DEVICE_ATTR(sync_for_device_bidir, SYSFS_PERMISSIONS, get_sync_for_device_bidir, sync_for_device_bidir); static DEVICE_ATTR(sync_for_device_bidir, SYSFS_PERMISSIONS, get_sync_for_device_bidir, sync_for_device_bidir);
static DEVICE_ATTR(flush_cpu_cache, SYSFS_PERMISSIONS, get_flush_cpu_cache, flush_cpu_cache);
static struct attribute *root_dev_attrs[] = { static struct attribute *root_dev_attrs[] = {
&dev_attr_buffer_address.attr, &dev_attr_buffer_address.attr,
...@@ -410,14 +349,12 @@ static struct attribute *root_dev_attrs[] = { ...@@ -410,14 +349,12 @@ static struct attribute *root_dev_attrs[] = {
&dev_attr_buffer_pages_d2h.attr, &dev_attr_buffer_pages_d2h.attr,
&dev_attr_buffer_address_bidir.attr, &dev_attr_buffer_address_bidir.attr,
&dev_attr_buffer_pages_bidir.attr, &dev_attr_buffer_pages_bidir.attr,
// &dev_attr_buffer_flush.attr,
&dev_attr_sync_for_cpu_h2d.attr, &dev_attr_sync_for_cpu_h2d.attr,
&dev_attr_sync_for_device_h2d.attr, &dev_attr_sync_for_device_h2d.attr,
&dev_attr_sync_for_cpu_d2h.attr, &dev_attr_sync_for_cpu_d2h.attr,
&dev_attr_sync_for_device_d2h.attr, &dev_attr_sync_for_device_d2h.attr,
&dev_attr_sync_for_cpu_bidir.attr, &dev_attr_sync_for_cpu_bidir.attr,
&dev_attr_sync_for_device_bidir.attr, &dev_attr_sync_for_device_bidir.attr,
&dev_attr_flush_cpu_cache.attr,
NULL NULL
}; };
......
...@@ -2,20 +2,18 @@ ...@@ -2,20 +2,18 @@
* *
* @brief Helper functions for various routines form x393.h which require several actions to get * @brief Helper functions for various routines form x393.h which require several actions to get
* reliable result. * reliable result.
*/
/* Copyright (C) 2016 Elphel, Inc
* *
* @copyright Copyright (C) 2016 Elphel, Inc
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
......
...@@ -2,20 +2,18 @@ ...@@ -2,20 +2,18 @@
* *
* @brief Helper functions for various routines form x393.h which require several actions to get * @brief Helper functions for various routines form x393.h which require several actions to get
* reliable result. * reliable result.
*/
/* Copyright (C) 2016 Elphel, Inc
* *
* @copyright Copyright (C) 2016 Elphel, Inc
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
...@@ -26,7 +24,7 @@ ...@@ -26,7 +24,7 @@
#include <asm/types.h> #include <asm/types.h>
#include "x393.h" #include "x393.h"
/** @brief Number of times to repeat register read sequence while waiting for /** @brief The number of times to repeat register read sequence while waiting for
* sequence number specified. * sequence number specified.
*/ */
#define REPEAT_READ 10 #define REPEAT_READ 10
......
/** /**
* @file x393_macro.h * @file x393_macro.h
* @brief This file contains various macros used in multiple files. * @brief This file contains various macros used in multiple files.
* @copyright Copyright (C) 2016 Elphel, Inc
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _X393_MACRO #ifndef _X393_MACRO
#define _X393_MACRO #define _X393_MACRO
...@@ -9,39 +23,46 @@ ...@@ -9,39 +23,46 @@
/** @brief Resolution of current/OEF pointer in bits */ /** @brief Resolution of current/OEF pointer in bits */
#define OFFSET256_CNTR_RES 26 #define OFFSET256_CNTR_RES 26
/** @brief The size of data transfer in bytes */
#define CHUNK_SIZE 32 #define CHUNK_SIZE 32
/** @brief The size of #interframe_params_t structure in double words */ /** @brief The size of #interframe_params_t structure in double words */
#define INTERFRAME_PARAMS_SZ 8 #define INTERFRAME_PARAMS_SZ 8
/** @brief Marker field in frame length double word value */
#define MARKER_FF 0xff000000 #define MARKER_FF 0xff000000
/** @brief #interframe_params_t has a guard field and its value must be equal to MARKER_FFFF, otherwise
* it has been overwritten, as JPEG can not have two subsequent 0xFF */
#define MARKER_FFFF 0xffff #define MARKER_FFFF 0xffff
/** @brief Mask for frame length extraction from double word value */
#define FRAME_LENGTH_MASK 0xffffff #define FRAME_LENGTH_MASK 0xffffff
/** @brief No operations with compressor interrupt control register */
#define IRQ_NOP 0 #define IRQ_NOP 0
/** @brief Clear compressor interrupt status */
#define IRQ_CLEAR 1 #define IRQ_CLEAR 1
/** @brief Disable compressor interrupt */
#define IRQ_DISABLE 2 #define IRQ_DISABLE 2
/** @brief Enable compressor interrupt */
#define IRQ_ENABLE 3 #define IRQ_ENABLE 3
/** @brief Convert size in bytes to size in double words */
#define BYTE2DW(x) ((x) >> 2) #define BYTE2DW(x) ((x) >> 2)
/** @brief Convert size in double words to size in bytes */
#define DW2BYTE(x) ((x) << 2) #define DW2BYTE(x) ((x) << 2)
/** @brief 4 bytes offset, this one comes from Python code x393_cmprs_afi.py */
// 4 bytes offset, this one comes from python code x393_cmprs_afi.py
#define ADJUSTMENT 4 #define ADJUSTMENT 4
#define INSERTED_BYTES(x) (((CHUNK_SIZE - ((((x) % CHUNK_SIZE) + CCAM_MMAP_META) % CHUNK_SIZE) - ADJUSTMENT) % CHUNK_SIZE ) + ADJUSTMENT) #define INSERTED_BYTES(x) (((CHUNK_SIZE - ((((x) % CHUNK_SIZE) + CCAM_MMAP_META) % CHUNK_SIZE) - ADJUSTMENT) % CHUNK_SIZE ) + ADJUSTMENT)
/* These macro were removed from sensor_common.h*/
#define X313_LENGTH_MASK 0xff000000 #define X313_LENGTH_MASK 0xff000000
/** @brief Subtract two offsets considering that the resulting offset can roll over the start of circular buffer */
#define X393_BUFFSUB(x, y) (((x) >= (y)) ? ((x)-(y)) : ((x) + (CCAM_DMA_SIZE -(y)))) #define X393_BUFFSUB(x, y) (((x) >= (y)) ? ((x)-(y)) : ((x) + (CCAM_DMA_SIZE -(y))))
/** @brief Add two offsets considering that the resulting offset car roll over the end of circular buffer */
#define X393_BUFFADD(x, y) ((((x) + (y)) <= CCAM_DMA_SIZE) ? ((x) + (y)) : ((x) - (CCAM_DMA_SIZE -(y)))) #define X393_BUFFADD(x, y) ((((x) + (y)) <= CCAM_DMA_SIZE) ? ((x) + (y)) : ((x) - (CCAM_DMA_SIZE -(y))))
#define TABLE_TYPE_QUANT 0 #define TABLE_TYPE_QUANT 0
#define TABLE_TYPE_CORING 1 #define TABLE_TYPE_CORING 1
#define TABLE_TYPE_FOCUS 2 #define TABLE_TYPE_FOCUS 2
#define TABLE_TYPE_HUFFMAN 3 #define TABLE_TYPE_HUFFMAN 3
/** /**
* @brief Converts file minor number to image compressor channel. * @brief Converts file minor number to image compressor channel.
* *
...@@ -49,7 +70,7 @@ ...@@ -49,7 +70,7 @@
* next nibble contains device type. Channel numbers and device type are defined in #driver_numbers.h * next nibble contains device type. Channel numbers and device type are defined in #driver_numbers.h
* @param[in] minor file minor number * @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 * @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) * @return compressor channel number in the range [0..#SENSOR_PORTS)
*/ */
static inline unsigned int minor_to_chn(unsigned int minor, unsigned int *dev_type) static inline unsigned int minor_to_chn(unsigned int minor, unsigned int *dev_type)
{ {
......
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