Commit aca0c9b9 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Add multichannel support to jpeghead.c, fix formatting

parent e14c7478
......@@ -117,29 +117,6 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
return 0;
}
/**
* @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)
{
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;
}
int circbuf_all_open(struct inode *inode, struct file *filp)
{
int res;
......@@ -747,6 +724,7 @@ static int circbuf_all_init(struct platform_device *pdev)
dev_err(dev, "couldn't get a major number %d.\n", CIRCBUF_MAJOR);
return res;
}
dev_info(dev, "registered MAJOR: %d\n", CIRCBUF_MAJOR);
res = init_ccam_dma_buf_ptr(pdev);
if (res < 0) {
......@@ -757,9 +735,12 @@ static int circbuf_all_init(struct platform_device *pdev)
dev_dbg(dev, "initialize circbuf wait queue\n");
init_waitqueue_head(&circbuf_wait_queue);
dev_dbg(dev, "initialize Huffman tables with default data\n");
jpeg_htable_init (); /// set default Huffman table, encode it for the FPGA
dev_info(dev, "registered MAJOR: %d\n", CIRCBUF_MAJOR);
res = jpeghead_init(pdev);
if (res < 0) {
dev_err(dev, "unable to initialize jpeghead module\n");
return res;
}
res = image_acq_init(pdev);
if (res < 0) {
dev_err(dev, "unable to initialize sensor_common module\n");
......
......@@ -19,18 +19,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
//#include <linux/module.h>
#include <linux/mm.h>
//#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
//#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/fs.h>
//#include <linux/string.h>
#include <linux/init.h>
//#include <linux/autoconf.h>
//#include <linux/time.h>
#include <linux/device.h>
//#include <linux/device.h>
#include <linux/platform_device.h>
//#include <asm/system.h>
//#include <asm/arch/memmap.h>
......@@ -61,16 +62,16 @@
//#include "cxdma.h"
//#include "circbuf.h"
//#include "sensor_common.h"
#include "exif.h"
//#include "exif.h"
#include "x393_macro.h"
#include "x393.h"
#define JPEG_HEADER_MAX_SIZE 0x300
static int huffman_fpga_programmed=0;
static struct device *g_dev_ptr = NULL;
/// All huffman tabels data to be read/written from the application
static struct huff_tables_t {
/**
* @brief All Huffman tables data to be read/written from the application
*/
struct huff_tables_t {
struct huffman_encoded_t header_huffman_tables[4];
unsigned long fpga_huffman_table[512];
union {
......@@ -82,45 +83,55 @@ static struct huff_tables_t {
unsigned char dht_ac1[5]; /// DHT AC1 header (all constants but the length)
};
};
} huff_tables;
}/* huff_tables */;
static struct jpeghead_priv_t {
struct huff_tables_t huff_tables;
unsigned int fpga_programmed;
unsigned long jpeg_h_sz; /// JPEG header size (no Exif)
unsigned char header[JPEG_HEADER_MAXSIZE];
} jpeghead_priv[IMAGE_CHN_NUM];
#define HEADER_COPY_SOF(x) {buf[bpl]=sizeof( x )+8 ; \
buf[bp++]=sizeof( x)/3; \
#define HEADER_COPY_SOF(x) {buf[bpl] = sizeof( x ) + 8; \
buf[bp++] = sizeof( x ) / 3; \
memcpy((void *) &buf[bp], (void *) ( x ), sizeof ( x )); \
bp+=sizeof ( x );}
#define HEADER_COPY_SOS(x) {buf[bp++]=sizeof( x )+6 ; \
buf[bp++]=sizeof( x)/2; \
bp += sizeof( x );}
#define HEADER_COPY_SOS(x) {buf[bp++] = sizeof( x ) + 6; \
buf[bp++] = sizeof( x ) / 2; \
memcpy((void *) &buf[bp], (void *) ( x ), sizeof ( x )); \
bp+=sizeof ( x );}
bp += sizeof( x );}
/**
* @brief just copy two quantization tables for the current frame (for the RTP streamer)
* @param params pointer to an array of parameters stored for the frame
* @param buf buffer to put the header to
* @return header length if successful, <0 - error
* @brief Copy two quantization tables for the current frame (for the RTP streamer)
* @param[in] params pointer to an array of parameters stored for the frame
* @param[out] buf buffer to put the header to
* @return header length if successful, < 0 - error
*/
int qtables_create(struct interframe_params_t * params, unsigned char * buf) {
int qtables_create(struct interframe_params_t *params, unsigned char *buf)
{
dev_dbg(g_dev_ptr, "params->quality2 = 0x%x\n", params->quality2);
int rslt=get_qtable(params->quality2, &buf[0], &buf[64]); /// will copy both quantization tables
if (rslt <0) return rslt; /// bad quality table
int rslt = get_qtable(params->quality2, &buf[0], &buf[64]); /// will copy both quantization tables
if (rslt < 0) return rslt; /// bad quality table
return 128;
}
/**
* @brief create JPEG header for the frame acquired earlier
* @param params pointer to an array of parameters stored for the frame
* @param buf buffer to put the header to
* @return header length if successful, <0 - error
* @brief Create JPEG header for the frame acquired earlier
* @param[in] params pointer to an array of parameters stored for the frame
* @param[our] buf buffer to put the header to
* @return header length if successful, < 0 - error
*/
int jpegheader_create(struct interframe_params_t * params, unsigned char * buf) {
int jpegheader_create(struct interframe_params_t *params, unsigned char *buf, unsigned int chn)
{
int bp=0; ///buffer pointer
int bpl; /// pointer to length word in the buffer
int rslt;
int len;
int header_sos; /// start of SOS (varaible)
int header_sos; /// start of SOS (variable)
const int header_yqtable= 0x19;
const int header_cqtable_hd= 0x59;
const int header_cqtable= 0x5e;
const int header_sof= 0x9e;
/// first constant part of the header - 0x19 bytes
/// first constant part of the header - 0x19 bytes
const unsigned char jfif1[0x19]={0xff, 0xd8, /// SOI start of image
0xff, 0xe0, /// APP0
0x00, 0x10, /// (16 bytes long)
......@@ -130,7 +141,7 @@ int jpegheader_create(struct interframe_params_t * params, unsigned char * buf)
0xff, 0xdb, /// DQT (define quantization table)
0x00, 0x43, /// 0x43 bytes long
0x00 }; /// table number + (bytes-1)<<4 (0ne byte - 0, 2 bytes - 0x10)
/// second constant part of the header (starting from byte 0x59 - 0x5 bytes)
/// second constant part of the header (starting from byte 0x59 - 0x5 bytes)
const unsigned char jfif2[0x5]= {0xff, 0xdb, /// DQT (define quantization table)
0x00, 0x43, /// 0x43 bytes long
......@@ -179,6 +190,9 @@ int jpegheader_create(struct interframe_params_t * params, unsigned char * buf)
0x05, 0x11,
0x06, 0x11,
0x07, 0x11};
struct huff_tables_t *huff_tables = &jpeghead_priv[chn].huff_tables;
if (buf==NULL) return -1; /// buffer is not provided
unsigned char *p = (char *)params;
......@@ -197,7 +211,7 @@ int jpegheader_create(struct interframe_params_t * params, unsigned char * buf)
buf[bp++]=0x8; /// 8bpp
buf[bp++]=params->height >> 8; buf[bp++]=params->height; /// big endian height
buf[bp++]=params->width >> 8; buf[bp++]=params->width; /// big endian width
/// copy SOF0 (constants combined with bayer shift for jp4diff/jp4hdr)
/// copy SOF0 (constants combined with bayer shift for jp4diff/jp4hdr)
switch (params->color) {
case COLORMODE_MONO6: /// monochrome, (4:2:0),
case COLORMODE_COLOR: /// color, 4:2:0, 18x18(old)
......@@ -220,8 +234,8 @@ int jpegheader_create(struct interframe_params_t * params, unsigned char * buf)
case COLORMODE_JP4DIFF: /// jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
case COLORMODE_JP4DIFF2: /// jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
HEADER_COPY_SOF(sof_jp4diff);
//header_sof
//bshift
//header_sof
//bshift
buf[header_sof+12+3*((4-params->byrshift) & 3)]=0; /// set quantization table 0 for the "base color"
break;
case COLORMODE_JP4HDR: /// jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
......@@ -231,32 +245,32 @@ int jpegheader_create(struct interframe_params_t * params, unsigned char * buf)
buf[header_sof+12+3*((6-params->byrshift) & 3)]=0; /// set quantization table 0 for the HDR color
break;
}
/// Include 4 huffman tables
memcpy((void *) &buf[bp], (void *) huff_tables.dht_dc0, 5); /// DHT DC0 header
/// Include 4 huffman tables
memcpy((void *) &buf[bp], (void *) huff_tables->dht_dc0, 5); /// DHT DC0 header
bp+=5;
len= (huff_tables.dht_dc0[2]<<8)+huff_tables.dht_dc0[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[0], len);
len= (huff_tables->dht_dc0[2]<<8)+huff_tables->dht_dc0[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables->header_huffman_tables[0], len);
bp+=len;
memcpy((void *) &buf[bp], (void *) huff_tables.dht_ac0, 5); /// DHT AC0 header
memcpy((void *) &buf[bp], (void *) huff_tables->dht_ac0, 5); /// DHT AC0 header
bp+=5;
len= (huff_tables.dht_ac0[2]<<8)+huff_tables.dht_ac0[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[1], len);
len= (huff_tables->dht_ac0[2]<<8)+huff_tables->dht_ac0[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables->header_huffman_tables[1], len);
bp+=len;
memcpy((void *) &buf[bp], (void *) huff_tables.dht_dc1, 5); /// DHT DC1 header
memcpy((void *) &buf[bp], (void *) huff_tables->dht_dc1, 5); /// DHT DC1 header
bp+=5;
len= (huff_tables.dht_dc1[2]<<8)+huff_tables.dht_dc1[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[2], len);
len= (huff_tables->dht_dc1[2]<<8)+huff_tables->dht_dc1[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables->header_huffman_tables[2], len);
bp+=len;
memcpy((void *) &buf[bp], (void *) huff_tables.dht_ac1, 5); /// DHT AC1 header
memcpy((void *) &buf[bp], (void *) huff_tables->dht_ac1, 5); /// DHT AC1 header
bp+=5;
len= (huff_tables.dht_ac1[2]<<8)+huff_tables.dht_ac1[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[3], len);
len= (huff_tables->dht_ac1[2]<<8)+huff_tables->dht_ac1[3]-3; /// table length itself, excluding 2 length bytes and type byte
memcpy((void *) &buf[bp], (void *) &huff_tables->header_huffman_tables[3], len);
bp+=len;
/// copy SOS0 (constants combined with bayer shift for jp4diff/jp4hdr)
/// copy SOS0 (constants combined with bayer shift for jp4diff/jp4hdr)
header_sos=bp;
buf[bp++]=0xff; buf[bp++]=0xda; /// SOS tag
buf[bp++]=0; /// high byte length - always 0
......@@ -302,25 +316,12 @@ int jpegheader_create(struct interframe_params_t * params, unsigned char * buf)
return bp; /// JPEG header length
}
static int minor_to_chn(unsigned int minor)
int jpeghead_open(struct inode *inode, struct file *filp)
{
return 0;
}
unsigned int minor = MINOR(inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
/*!=================================================================
*! JPEG header file support
*!=================================================================*/
//! make it blocking to use shared resource - jpeg header that may need re-calculation for different requests?
//! or use individual header arrays?
int jpeghead_open(struct inode *inode, struct file *filp) { // set filesize
struct jpeghead_pd * privData;
privData= (struct jpeghead_pd *) kmalloc(sizeof(struct jpeghead_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
filp->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
privData-> size=0; ///undefined yet
jpeghead_priv[chn].jpeg_h_sz = 0;
inode->i_size=JPEG_HEADER_MAXSIZE; /// not the actual size
return 0;
}
......@@ -338,16 +339,14 @@ int jpeghead_open(struct inode *inode, struct file *filp) { // set filesize
*! file at the very beginning and return 0 if OK, -EINVAL if
*! frame header is not found for the specified offset
*!================================================================*/
loff_t jpeghead_lseek(struct file * file, loff_t offset, int orig,
struct interframe_params_t *fp){
loff_t jpeghead_lseek(struct file *file, loff_t offset, int orig,
struct interframe_params_t *fp)
{
int rp;
struct jpeghead_pd * privData;
//struct interframe_params_t * fp;
privData = (struct jpeghead_pd *) file->private_data;
dev_dbg(g_dev_ptr, "orig = %d, offset = 0x%x\n", orig, (int)offset);
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
dev_dbg(g_dev_ptr, "start processing LSEEK operation, minor = 0x%x, offset = 0x%llx, orig = 0x%x", minor, offset, orig);
switch (orig)
{
......@@ -359,30 +358,20 @@ loff_t jpeghead_lseek(struct file * file, loff_t offset, int orig,
break;
case SEEK_END:
if (offset <= 0) {
file->f_pos = privData->size + offset;
} else { //! New functionality
file->f_pos=0; // anyway reset it to 0
/*
* move below two lines to circbuf_all_lseek to remove ccam_dma_buf_ptr and simplify dependencies
rp= (offset >>2) & (~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
*/
//if ((fp->signffff != 0xffff) || //! signature is overwritten
if ((fp->signffff != MARKER_FFFF) || //! signature is overwritten
file->f_pos = jpeghead_priv[chn].jpeg_h_sz + offset;
} else {
file->f_pos = 0; // reset it to 0 anyway
if ((fp->signffff != MARKER_FFFF) || // signature is overwritten
((fp->timestamp_sec) & X313_LENGTH_MASK)) return -EINVAL; //! acquisition of this frame is not done yet - length word high byte is non-zero
///FIXME: pp_index=fp->past_index; /// unsigned short
/// if (pp_index>=PASTPARS_SAVE_ENTRIES) return -EINVAL; /// wrong index
/// privData->size= jpegheader_create( pastpars[pp_index].past_pars, privData->header);
if ((offset & 0x1f)==0x2) privData->size= qtables_create(fp, privData->header); /// just qunatization tables (128 bytes) - for the streamer
else privData->size= jpegheader_create(fp, privData->header); /// full JPEG header
if (privData->size <0 ) {
privData->size=0;
return -EINVAL; /// error in header
if ((offset & 0x1f) == 0x2)
jpeghead_priv[chn].jpeg_h_sz = qtables_create(fp, jpeghead_priv[chn].header); /// just qunatization tables (128 bytes) - for the streamer
else
jpeghead_priv[chn].jpeg_h_sz = jpegheader_create(fp, jpeghead_priv[chn].header, chn); /// full JPEG header
if (jpeghead_priv[chn].jpeg_h_sz < 0) {
jpeghead_priv[chn].jpeg_h_sz = 0;
return -EINVAL; // error in header
}
return ( file->f_pos ); //! it is 0
return ( file->f_pos ); // it is 0
}
break;
default:
......@@ -391,28 +380,32 @@ loff_t jpeghead_lseek(struct file * file, loff_t offset, int orig,
/// truncate position
if (file->f_pos < 0) {
file->f_pos = 0;
return(-EOVERFLOW);
return -EOVERFLOW;
}
if (file->f_pos > privData->size) {
file->f_pos = privData->size;
if (file->f_pos > jpeghead_priv[chn].jpeg_h_sz) {
file->f_pos = jpeghead_priv[chn].jpeg_h_sz;
}
return ( file->f_pos );
return file->f_pos;
}
ssize_t jpeghead_read(struct file * file, char * buf, size_t count, loff_t *off) {
ssize_t jpeghead_read(struct file *file, char *buf, size_t count, loff_t *off)
{
unsigned long p;
struct jpeghead_pd * privData;
privData = (struct jpeghead_pd *) file->private_data;
dev_dbg(g_dev_ptr, "reading from jpeghead\n");
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
dev_dbg(g_dev_ptr, "reading from jpeghead, minor = 0x%x, off = 0x%lld\n", minor, off);
p = *off;
if(p >= privData->size)
p = privData->size;
if((p + count) > privData->size) { /// truncate count
count = privData->size - p;
if (p >= jpeghead_priv[chn].jpeg_h_sz)
p = jpeghead_priv[chn].jpeg_h_sz;
if ((p + count) > jpeghead_priv[chn].jpeg_h_sz) { /// truncate count
count = jpeghead_priv[chn].jpeg_h_sz - p;
}
if(count) {
if(copy_to_user(buf, &privData->header[p], count)) return -EFAULT;
if (count) {
if (copy_to_user(buf, &jpeghead_priv[chn].header[p], count))
return -EFAULT;
*off += count;
}
return count;
......@@ -427,13 +420,9 @@ ssize_t jpeghead_read(struct file * file, char * buf, size_t count, loff_t *off)
* - 4 bytes - number of symbols in each table (calculated)
*/
int huffman_open(struct inode *inode, struct file *filp) { // set filesize
struct huffman_pd * privData;
privData= (struct huffman_pd *) kmalloc(sizeof(struct huffman_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
filp->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
inode->i_size = sizeof(huff_tables);
int huffman_open(struct inode *inode, struct file *filp)
{
inode->i_size = sizeof(struct huff_tables_t);
return 0;
}
......@@ -451,12 +440,12 @@ int huffman_open(struct inode *inode, struct file *filp) { // set filesize
*! those commands do not move the file pointer (return current),
*! or negative in the case of error (calculate FPGA table)
*!================================================================*/
loff_t huffman_lseek(struct file * file, loff_t offset, int orig){
// orig 0: position from begning
// orig 1: relative from current position
// orig 2: position from last address
loff_t huffman_lseek(struct file *file, loff_t offset, int orig)
{
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
dev_dbg(g_dev_ptr, "start processing LSEEK operation, minor = 0x%x, offset = 0x%llx, orig = 0x%x", minor, offset, orig);
switch (orig)
{
......@@ -468,21 +457,20 @@ loff_t huffman_lseek(struct file * file, loff_t offset, int orig){
break;
case SEEK_END:
if (offset <= 0) {
file->f_pos = sizeof(huff_tables) + offset;
} else { //! New functionality
file->f_pos = sizeof(struct huff_tables_t) + offset;
} else {
switch (offset) {
case LSEEK_HUFFMAN_DC0: file->f_pos=0; break;
case LSEEK_HUFFMAN_AC0: file->f_pos=1*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_DC1: file->f_pos=2*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_AC1: file->f_pos=3*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_FPGATAB: file->f_pos=4*sizeof(struct huffman_encoded_t);break;
case LSEEK_HUFFMAN_DEFAULT: jpeg_htable_init(); break; // no change to file pointer
case LSEEK_HUFFMAN_DEFAULT: jpeg_htable_init(chn); break; // no change to file pointer
case LSEEK_HUFFMAN_FPGACALC:
if (jpeg_htable_fpga_encode () <0) return -EINVAL;
if (jpeg_htable_fpga_encode (chn) < 0) return -EINVAL;
break;
case LSEEK_HUFFMAN_FPGAPGM: jpeg_htable_fpga_pgm(minor_to_chn(minor)); break;
case LSEEK_HUFFMAN_FPGAPGM: jpeg_htable_fpga_pgm(chn); break;
default: return -EINVAL;
}
return ( file->f_pos );
}
......@@ -495,35 +483,47 @@ loff_t huffman_lseek(struct file * file, loff_t offset, int orig){
file->f_pos = 0;
return(-EOVERFLOW);
}
if (file->f_pos > sizeof(huff_tables)) file->f_pos = sizeof(huff_tables);
if (file->f_pos > sizeof(struct huff_tables_t)) file->f_pos = sizeof(struct huff_tables_t);
return ( file->f_pos );
}
ssize_t huffman_read(struct file * file, char * buf, size_t count, loff_t *off) {
ssize_t huffman_read(struct file *file, char *buf, size_t count, loff_t *off)
{
unsigned long p;
unsigned char * uc_huff_tables= (unsigned char *) &huff_tables;
dev_dbg(g_dev_ptr, "reading from huffman\n");
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
unsigned char *uc_huff_tables = (unsigned char *) &jpeghead_priv[chn].huff_tables;
dev_dbg(g_dev_ptr, "reading from huffman, minor = 0x%x, off = 0x%llx\n", minor, off);
p = *off;
if(p >= sizeof(huff_tables)) p = sizeof(huff_tables);
if((p + count) > sizeof(huff_tables)) count = sizeof(huff_tables) - p; /// truncate count
if (p >= sizeof(struct huff_tables_t))
p = sizeof(struct huff_tables_t);
if ((p + count) > sizeof(struct huff_tables_t))
count = sizeof(struct huff_tables_t) - p; /// truncate count
if(count) {
if(copy_to_user(buf, &uc_huff_tables[p], count)) return -EFAULT;
if (copy_to_user(buf, &uc_huff_tables[p], count)) return -EFAULT;
*off += count;
}
return count;
}
ssize_t huffman_write(struct file * file, const char * buf, size_t count, loff_t *off) {
ssize_t huffman_write(struct file *file, const char *buf, size_t count, loff_t *off)
{
unsigned long p;
unsigned char * uc_huff_tables= (unsigned char *) &huff_tables;
dev_dbg(g_dev_ptr, "writing to huffman\n");
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
unsigned char * uc_huff_tables= (unsigned char *) &jpeghead_priv[chn].huff_tables;
dev_dbg(g_dev_ptr, "writing to huffman, minor = 0x%x, off = 0x%llx\n", minor, off);
p = *off;
if (p >= sizeof(huff_tables)) p = sizeof(huff_tables);
if( (p + count) > sizeof(huff_tables)) count = sizeof(huff_tables) - p; /// truncate count
if (p >= sizeof(struct huff_tables_t))
p = sizeof(struct huff_tables_t);
if ((p + count) > sizeof(struct huff_tables_t))
count = sizeof(struct huff_tables_t) - p; /// truncate count
if (count) {
if (copy_from_user(&uc_huff_tables[p],buf, count)) return -EFAULT;
if (copy_from_user(&uc_huff_tables[p], buf, count)) return -EFAULT;
}
return count;
......@@ -532,15 +532,16 @@ ssize_t huffman_write(struct file * file, const char * buf, size_t count, loff_t
/**
* @brief Initialize Huffman tables with default data
*/
void jpeg_htable_init (void) {
void jpeg_htable_init(unsigned int chn)
{
unsigned char dc0[]={0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///. number of codes of each length 1..16 (12 total)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /// symbols encoded (12)
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // number of codes of each length 1..16 (12 total)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // symbols encoded (12)
0x08, 0x09, 0x0a, 0x0b};
unsigned char ac0[]={0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, /// - counts of codes of each length - 1..16 - total a2
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, /// symbols encoded (0xa2)
0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, // counts of codes of each length - 1..16 - total a2
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, // symbols encoded (0xa2)
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
......@@ -566,6 +567,7 @@ void jpeg_htable_init (void) {
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b};
unsigned char ac1[]={0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
......@@ -589,90 +591,99 @@ void jpeg_htable_init (void) {
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa};
struct huff_tables_t *huff_tables = &jpeghead_priv[chn].huff_tables;
dev_dbg(g_dev_ptr, "initialize Huffman table with default data\n");
memset ((void*) &huff_tables,0, sizeof(huff_tables));
memcpy ((void*) huff_tables.header_huffman_tables[0].bits,dc0, sizeof(dc0));
memcpy ((void*) huff_tables.header_huffman_tables[1].bits,ac0, sizeof(ac0));
memcpy ((void*) huff_tables.header_huffman_tables[2].bits,dc1, sizeof(dc1));
memcpy ((void*) huff_tables.header_huffman_tables[3].bits,ac1, sizeof(ac1));
jpeg_htable_fpga_encode ();
memset ((void*) huff_tables, 0, sizeof(struct huff_tables_t));
memcpy ((void*) huff_tables->header_huffman_tables[0].bits, dc0, sizeof(dc0));
memcpy ((void*) huff_tables->header_huffman_tables[1].bits, ac0, sizeof(ac0));
memcpy ((void*) huff_tables->header_huffman_tables[2].bits, dc1, sizeof(dc1));
memcpy ((void*) huff_tables->header_huffman_tables[3].bits, ac1, sizeof(ac1));
jpeg_htable_fpga_encode(chn);
}
/**
* @brief encode all 4 Huffman tables into FPGA format
* @brief Encode all 4 Huffman tables into FPGA format
* additionally calculates number of symbols in each table
* @return OK - 0, -1 - too many symbols, -2 bad table, -3 - bad table number
*/
int jpeg_htable_fpga_encode (void) {
int jpeg_htable_fpga_encode(unsigned int chn)
{
int ntab, i, rslt, a, length;
const unsigned char dht_headers[20]={ /// length will be inserted later
const unsigned char dht_headers[20] = { /// length will be inserted later
0xff, 0xc4, 0x00, 0x00, 0x00,
0xff, 0xc4, 0x00, 0x00, 0x10,
0xff, 0xc4, 0x00, 0x00, 0x01,
0xff, 0xc4, 0x00, 0x00, 0x11 };
struct huffman_fpga_code_t codes[256];
unsigned long * icodes = (unsigned long *) codes;
huffman_fpga_programmed=0; /// mark FPGA table as needed to be programmed
dev_dbg(g_dev_ptr, "encode all Huffman tables into FPGA format\n");
/// Fill in the table headers:
memcpy ((void*) huff_tables.dht_all, (void*) dht_headers, sizeof(dht_headers)); /// all 4 headers (with zero length)
for (ntab=0; ntab<4; ntab++) {
struct huff_tables_t *huff_tables = &jpeghead_priv[chn].huff_tables;
dev_dbg(g_dev_ptr, "channel %d; encode all Huffman tables into FPGA format\n", chn);
jpeghead_priv[chn].fpga_programmed = 0;
/// Fill in the table headers:
memcpy((void*) huff_tables->dht_all, (void*) dht_headers, sizeof(dht_headers)); /// all 4 headers (with zero length)
for (ntab = 0; ntab < 4; ntab++) {
dev_dbg(g_dev_ptr, "ntab = %d\n", ntab);
memset (codes,0,sizeof(codes));
if ((rslt=jpeg_prep_htable (&(huff_tables.header_huffman_tables[ntab]), codes)) < 0 ) return rslt;
memset(codes, 0, sizeof(codes));
if ((rslt = jpeg_prep_htable(&huff_tables->header_huffman_tables[ntab], codes)) < 0) return rslt;
if (ntab & 1) {
a=((ntab & 2)<<7);
for (i=0; i<256;i+=16) {
memcpy ((void*) &(huff_tables.fpga_huffman_table[a]), (void*) &codes[i], 60); /// all but DC column
a+=16;
a = ((ntab & 2) << 7);
for (i = 0; i < 256; i += 16) {
memcpy((void*) &(huff_tables->fpga_huffman_table[a]), (void*) &codes[i], 60); /// all but DC column
a += 16;
}
} else {
a=((ntab & 2)<<7)+0x0f; /// in FPGA DC use spare parts of AC table
for (i=0; i<16;i++) {
huff_tables.fpga_huffman_table[a]= icodes[i];
a+=16;
a = ((ntab & 2) << 7) + 0x0f; /// in FPGA DC use spare parts of AC table
for (i = 0; i < 16; i++) {
huff_tables->fpga_huffman_table[a] = icodes[i];
a += 16;
}
}
/// Fill in the table headers:
length=19; /// 2 length bytes, 1 type byte, 16 lengths bytes
for (i=0; i<16; i++) length += huff_tables.header_huffman_tables[ntab].bits[i]; /// first 16 bytes in each table number of symbols
huff_tables.dht_all[(5*ntab)+2]=length >> 8; /// high byte (usually 0)
huff_tables.dht_all[(5*ntab)+3]=length& 0xff; /// low byte
/// Fill in the table headers:
length = 19; /// 2 length bytes, 1 type byte, 16 lengths bytes
for (i = 0; i < 16; i++) length += huff_tables->header_huffman_tables[ntab].bits[i]; /// first 16 bytes in each table number of symbols
huff_tables->dht_all[(5 * ntab) + 2] = length >> 8; /// high byte (usually 0)
huff_tables->dht_all[(5 * ntab) + 3] = length& 0xff; /// low byte
}
dev_dbg(g_dev_ptr, "FPGA Huffman table:\n");
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, &huff_tables.fpga_huffman_table[0], sizeof(huff_tables.fpga_huffman_table));
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, &huff_tables->fpga_huffman_table[0], sizeof(huff_tables->fpga_huffman_table));
return 0;
}
/**
* @brief check if the FPGA is programmed to the new Huffman table
* @brief Check if the FPGA is programmed to the new Huffman table
* @param[in] chn compressor channel number
* @return 1 - programmed, 0 - not programmed
*/
int jpeg_htable_is_programmed(void) {
return huffman_fpga_programmed;
int jpeg_htable_is_programmed(unsigned int chn)
{
return jpeghead_priv[chn].fpga_programmed;
}
/**
* @brief program FPGA Huffman table (fram static array)
* @param[in] chn compressor channle number
* @param[in] chn compressor channel number
* return none
*/
void jpeg_htable_fpga_pgm(unsigned int chn)
{
int i;
x393_cmprs_table_addr_t table_addr;
struct huff_tables_t *huff_tables = &jpeghead_priv[chn].huff_tables;
table_addr.addr32 = 0;
table_addr.type = 3;
x393_cmprs_tables_address(table_addr, chn);
for (i = 0; i < sizeof(huff_tables.fpga_huffman_table); i++) {
x393_cmprs_tables_data((u32)huff_tables.fpga_huffman_table[i], chn);
for (i = 0; i < sizeof(huff_tables->fpga_huffman_table); i++) {
x393_cmprs_tables_data((u32)huff_tables->fpga_huffman_table[i], chn);
}
huffman_fpga_programmed=1;
jpeghead_priv[chn].fpga_programmed = 1;
}
/**
......@@ -683,8 +694,7 @@ void jpeg_htable_fpga_pgm(unsigned int chn)
* @param hcodes combined (length<<16) | code table for each symbol
* @return OK- 0, -1 - too many symbols, -2 bad table
*/
///Does it depend on no missing symbols?
int jpeg_prep_htable (struct huffman_encoded_t * htable, struct huffman_fpga_code_t * hcodes)
int jpeg_prep_htable(struct huffman_encoded_t *htable, struct huffman_fpga_code_t *hcodes)
{
int p, i, l, si, numsymbols;
unsigned int code;
......@@ -729,4 +739,15 @@ int jpeg_prep_htable (struct huffman_encoded_t * htable, struct huffman_fpga_cod
return 0;
}
MODULE_LICENSE("GPL");
int jpeghead_init(struct platform_device *pdev)
{
int i;
g_dev_ptr = &pdev->dev;
for (i = 0; i < IMAGE_CHN_NUM; i++) {
jpeghead_priv[i].fpga_programmed = 0;
jpeg_htable_init(i);
}
return 0;
}
......@@ -10,7 +10,7 @@ struct huffman_fpga_code_t {
unsigned short length; /// code length
};
int qtables_create (struct interframe_params_t * params, unsigned char * buf);
int jpegheader_create(struct interframe_params_t * params, unsigned char * buf);
int jpegheader_create(struct interframe_params_t * params, unsigned char * buf, unsigned int chn);
int jpeghead_open (struct inode *inode, struct file *filp); // set filesize
loff_t jpeghead_lseek (struct file * file, loff_t offset, int orig, struct interframe_params_t *fp);
ssize_t jpeghead_read (struct file * file, char * buf, size_t count, loff_t *off);
......@@ -35,10 +35,12 @@ struct huffman_pd {
int minor;/// should be the first, same as in circbuf_pd
};
int jpeg_htable_is_programmed(void);
void jpeg_htable_init (void);
int jpeg_htable_fpga_encode (void);
void jpeg_htable_fpga_pgm (unsigned int chn);
int jpeg_prep_htable (struct huffman_encoded_t * htable, struct huffman_fpga_code_t * hcodes);
int jpeg_htable_is_programmed(unsigned int chn);
void jpeg_htable_init(unsigned int chn);
int jpeg_htable_fpga_encode(unsigned int chn);
void jpeg_htable_fpga_pgm(unsigned int chn);
int jpeg_prep_htable(struct huffman_encoded_t * htable, struct huffman_fpga_code_t * hcodes);
int jpeghead_init(struct platform_device *pdev);
#endif /* _JPEGHEAD */
......@@ -25,33 +25,33 @@
*/
//copied from cxi2c.c - TODO:remove unneeded
#include <linux/module.h>
//#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
//#include <linux/slab.h>
//#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/string.h>
//#include <linux/fs.h>
//#include <linux/string.h>
#include <linux/init.h>
//#include <linux/autoconf.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
//#include <linux/vmalloc.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
//#include <linux/of.h>
//#include <linux/of_device.h>
//#include <asm/system.h>
#include <asm/byteorder.h> // endians
#include <asm/io.h>
//#include <asm/byteorder.h> // endians
//#include <asm/io.h>
//#include <asm/arch/hwregs/intr_vect_defs.h> /// ETRAX interrupt registers
#include <asm/irq.h>
//#include <asm/irq.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
//#include <asm/delay.h>
//#include <asm/uaccess.h>
#include <elphel/driver_numbers.h>
#include <elphel/c313a.h>
//#include <asm/elphel/fpgaconfa.h>
......@@ -775,11 +775,12 @@ int image_acq_stop(struct platform_device *pdev)
return 0;
}
static const struct of_device_id elphel393_sensor_of_match[] = {
{ .compatible = "elphel,elphel393-sensor-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_sensor_of_match);
//static const struct of_device_id elphel393_sensor_of_match[] = {
// { .compatible = "elphel,elphel393-sensor-1.00" },
// { /* end of list */ }
//};
//MODULE_DEVICE_TABLE(of, elphel393_sensor_of_match);
/*static struct platform_driver elphel393_sensor_common = {
.probe = image_acq_init,
......@@ -792,6 +793,6 @@ MODULE_DEVICE_TABLE(of, elphel393_sensor_of_match);
//module_platform_driver(elphel393_sensor_common);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(IMAGEACQ_DRIVER_NAME);
//MODULE_LICENSE("GPL");
//MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
//MODULE_DESCRIPTION(IMAGEACQ_DRIVER_NAME);
......@@ -5,6 +5,8 @@
#ifndef _X393_MACRO
#define _X393_MACRO
#include <elphel/driver_numbers.h>
/** @brief Number of image channels */
#define IMAGE_CHN_NUM 4
......@@ -39,4 +41,27 @@
#define X393_BUFFSUB(x, y) (((x) >= (y)) ? ((x)-(y)) : ((x) + (CCAM_DMA_SIZE -(y))))
#define X393_BUFFADD(x, y) ((((x) + (y)) <= CCAM_DMA_SIZE) ? ((x) + (y)) : ((x) - (CCAM_DMA_SIZE -(y))))
/**
* @brief Converts file minor number to image compressor channel.
*
* This function assumes that the least significant nibble of minor number 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)
{
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;
}
#endif /* _X393_MACRO */
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