Commit 60f29555 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

merged with master

parents 50e586e1 0f25f13b
Loading
Loading
Loading
Loading
+1155 −7

File changed.

Preview size limit exceeded, changes collapsed.

+116 −0
Original line number Original line Diff line number Diff line
/** @file ahci_elphel_ext.h
 *
 * @brief Elphel AHCI SATA platform driver for Elphel393 camera. This module provides
 * additional functions which allows to use a part of a disk (or entire disk) as a
 * raw circular buffer.
 *
 * @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/>.
 */

#include <uapi/elphel/ahci_cmd.h>
#include "../elphel/circbuf.h"

#ifndef _AHCI_ELPHEL_EXT
#define _AHCI_ELPHEL_EXT


#define IRQ_SIMPLE                (1 << 0)       ///< Flag indicating that IRQ corresponds to internal command and should not be
                                                 ///< processed in ahci_handle_port_interrupt
#define DISK_BUSY                 (1 << 1)       ///< Flag indicating that disk is currently busy. Access to this flag should be protected by
                                                 ///< spin locks to prevent race conditions
#define PROC_CMD                  (1 << 2)       ///< Processing driver's internal command is in progress
#define LAST_BLOCK                (1 << 3)       ///< Flag indicating that the remaining chunk of data will be recorded
#define DELAYED_FINISH            (1 << 4)       ///< Flag indicating that recording should be stopped right after the last chunk of data is written
#define LOCK_TAIL                 (1 << 5)       ///< Lock current command slot until all data buffers are assigned and the frame is aligned
#define CMD_FIS_LEN               5              ///< The length of a command FIS in double words
#define ADDR_MASK_28_BIT          ((u64)0xfffffff)///< This is used to get 28-bit address from 64-bit value
#define MAX_PRDT_LEN              0x3fffff       ///< A maximum of length of 4MB may exist for PRDT entry
#define MAX_DATA_CHUNKS           9              ///< An array or JPEG frame chunks contains pointers to JPEG leading marker,
                                                 ///< JPEG header, Exif data if present, stuffing bytes chunk which aligns
                                                 ///< the frame size to disk sector boundary, JPEG data which
                                                 ///< can be split into two chunks, align buffers, JPEG
                                                 ///< trailing marker, and pointer to a buffer containing the remainder of a
                                                 ///< frame. Nine chunks of data in total.
#define DEFAULT_PORT_NUM          0              ///< Default port number
#define ALIGNMENT_SIZE            32             ///< Align buffers length to this amount of bytes
#define MAX_SGL_LEN               168            ///< Maximum number of entries in PRDT table. HW max is 64k.
                                                 ///< Set this value the same as AHCI_MAX_SG in ahci.h
#define MAX_CMD_SLOTS             4              ///< Maximum number of frames which will be processed at the same time
#define MAX_LBA_COUNT             0xff           ///< Maximum number of sectors for READ DMA or WRITE DMA commands
#define MAX_LBA_COUNT_EXT         0xffff         ///< Maximum number of sectors for READ DMA EXT or WRITE_DMA EXT commands
#define PHY_BLOCK_SIZE            512            ///< Physical disk block size
#define JPEG_MARKER_LEN           2              ///< The size in bytes of JPEG marker
#define JPEG_SIZE_LEN             2              ///< The size in bytes of JPEG marker length field
#define INCLUDE_REM               1              ///< Include REM buffer to total size calculation
#define EXCLUDE_REM               0              ///< Exclude REM buffer from total size calculation

/** This structure holds raw device buffer pointers */
struct drv_pointers {
	uint64_t lba_start;                          ///< raw buffer starting LBA
	uint64_t lba_end;                            ///< raw buffer ending LBA
	uint64_t lba_write;                          ///< current write pointer inside raw buffer
	uint16_t wr_count;                           ///< the number of LBA to write next time
};

/** Container structure for frame buffers */
struct frame_buffers {
	struct fvec exif_buff;                       ///< Exif buffer
	struct fvec jpheader_buff;                   ///< JPEG header buffer
	struct fvec trailer_buff;                    ///< buffer for trailing marker
	struct fvec common_buff;                     ///< common buffer where other parts are combined
	struct fvec rem_buff;                        ///< remainder from previous frame
};

/** Symbolic names for slots in buffer pointers. Buffer alignment function relies on the order of these names, so
 * new names can be added but the overall order should not be changed */
enum {
	CHUNK_LEADER,                                ///< pointer to JPEG leading marker
	CHUNK_EXIF,                                  ///< pointer to Exif buffer
	CHUNK_HEADER,                                ///< pointer to JPEG header data excluding leading marker
	CHUNK_COMMON,                                ///< pointer to common buffer
	CHUNK_DATA_0,                                ///< pointer to JPEG data
	CHUNK_DATA_1,                                ///< pointer to the second half of JPEG data if a frame crosses circbuf boundary
	CHUNK_TRAILER,                               ///< pointer to JPEG trailing marker
	CHUNK_ALIGN,                                 ///< pointer to buffer where the second part of JPEG data should be aligned
	CHUNK_REM                                    ///< pointer to buffer containing the remainder of current frame. It will be recorded during next transaction
};

/** AHCI driver private structure */
struct elphel_ahci_priv {
	u32 clb_offs;                                ///< CLB offset, received from device tree
	u32 fb_offs;                                 ///< FB offset, received from device tree
	u32 base_addr;                               ///< controller base address
	u32 flags;                                   ///< flags indicating current state of the driver. Access to #DISK_BUSY flags is protected with
	                                             ///< a spin lock
	int curr_cmd;                                ///< current ATA command
	size_t max_data_sz;                          ///< maximum data size (in bytes) which can be processed with current ATA command
	struct drv_pointers lba_ptr;                 ///< disk buffer pointers
	struct frame_buffers fbuffs[MAX_CMD_SLOTS];  ///< a set of buffers for each command
	struct fvec data_chunks[MAX_CMD_SLOTS][MAX_DATA_CHUNKS];///< a set of vectors pointing to data buffers for each command
	struct fvec sgl[MAX_SGL_LEN];                ///< an array of data buffers mapped for next transaction
	int sg_elems;                                ///< the number of S/G vectors mapped for next transaction in @e sgl array
	int curr_data_chunk;                         ///< index of a data chunk used during last transaction
	size_t curr_data_offset;                     ///< offset of the last byte in a data chunk pointed to by @e curr_data_chunk
	size_t head_ptr;                             ///< pointer to command slot which will be written next
	size_t tail_ptr;                             ///< pointer to next free command slot
	spinlock_t flags_lock;                       ///< controls access to #DISK_BUSY flag in @e flags variable.
	                                             ///< This flag controls access to disk write operations either from
	                                             ///< the the driver itself or from the system.  Mutex is not used
	                                             ///< because this flag is accessed from interrupt context
	struct tasklet_struct bh;                    ///< command processing tasklet
	struct device *dev;                          ///< pointer to parent device structure
};

#endif /* _AHCI_ELPHEL_EXT */
+31 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@
#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 <linux/uio.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <uapi/elphel/x393_devices.h>
#include <uapi/elphel/x393_devices.h>
#include <uapi/elphel/c313a.h>
#include <uapi/elphel/c313a.h>
@@ -108,6 +109,36 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
	return 0;
	return 0;
}
}


ssize_t circbuf_get_ptr(int sensor_port, size_t offset, size_t len, struct fvec *vect_0, struct fvec *vect_1)
{
	int ret = 1;

	if (offset > CCAM_DMA_SIZE || sensor_port >= SENSOR_PORTS)
		return -EINVAL;

	if (offset + len < CCAM_DMA_SIZE) {
		// the image is not split
		vect_0->iov_base = &circbuf_priv[sensor_port].buf_ptr[BYTE2DW(offset)];
		vect_0->iov_dma = circbuf_priv[sensor_port].phys_addr + offset;
		vect_0->iov_len = len;
		vect_1->iov_base = NULL;
		vect_1->iov_len = 0;
		vect_1->iov_dma = 0;
	} else {
		// the image is split into two segments
		vect_0->iov_base = &circbuf_priv[sensor_port].buf_ptr[BYTE2DW(offset)];
		vect_0->iov_dma = circbuf_priv[sensor_port].phys_addr + offset;
		vect_0->iov_len = CCAM_DMA_SIZE - offset;
		vect_1->iov_base = circbuf_priv[sensor_port].buf_ptr;
		vect_1->iov_dma = circbuf_priv[sensor_port].phys_addr;
		vect_1->iov_len = len - vect_0->iov_len;
		ret = 2;
	}

	return ret;
}
EXPORT_SYMBOL_GPL(circbuf_get_ptr);

/**
/**
 * @brief Process circular buffer file opening and define further action in accordance
 * @brief Process circular buffer file opening and define further action in accordance
 * with minor file number.
 * with minor file number.
+8 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,12 @@


#include <linux/poll.h>
#include <linux/poll.h>


struct fvec {
	void *iov_base;                              ///< pointer to allocated buffer
	size_t iov_len;                              ///< the size (in bytes) of allocated buffer; set after allocation and is not modified during buffer lifetime
	dma_addr_t iov_dma;                          ///< buffer physical address
};

/** @brief Circular buffer private data */
/** @brief Circular buffer private data */
struct circbuf_priv_t {
struct circbuf_priv_t {
	int                 minor;                             ///< device file minor number
	int                 minor;                             ///< device file minor number
@@ -75,4 +81,6 @@ extern unsigned char circbuf_byrshift;
#endif
#endif
/* end of debug code */
/* end of debug code */


ssize_t circbuf_get_ptr(int sensor_port, size_t offset, size_t len, struct fvec *vect_0, struct fvec *vect_1);

#endif /* _CIRCBUF_H */
#endif /* _CIRCBUF_H */
+31 −1
Original line number Original line Diff line number Diff line
@@ -54,7 +54,7 @@
#include "exif393.h"
#include "exif393.h"


#define D(x)
#define D(x)
//#define D(x) printk("%s:%d:",__FILE__,__LINE__);x
//#define D(x) printk(">>> %s:%d:",__FILE__,__LINE__);x




//Major
//Major
@@ -90,6 +90,7 @@ static int aexif_wp[SENSOR_PORTS] = {1,1,1,1}; // frame write pointer in
static int aexif_enabled[SENSOR_PORTS] =   {0,0,0,0}; // enable storing of frame meta data, enable reading Exif data
static int aexif_enabled[SENSOR_PORTS] =   {0,0,0,0}; // enable storing of frame meta data, enable reading Exif data
static int aexif_valid[SENSOR_PORTS] =     {0,0,0,0}; // Exif tables and buffer are valid.
static int aexif_valid[SENSOR_PORTS] =     {0,0,0,0}; // Exif tables and buffer are valid.
static char * ameta_buffer[SENSOR_PORTS]=  {NULL,NULL,NULL,NULL}; // dynamically allocated buffer to store frame meta data.
static char * ameta_buffer[SENSOR_PORTS]=  {NULL,NULL,NULL,NULL}; // dynamically allocated buffer to store frame meta data.
static char exif_tmp_buff[MAX_EXIF_SIZE];


//static char * meta_buffer=NULL; // dynamically allocated buffer to store frame meta data.
//static char * meta_buffer=NULL; // dynamically allocated buffer to store frame meta data.
// page 0 - temporary storage, 1..MAX_EXIF_FRAMES - buffer
// page 0 - temporary storage, 1..MAX_EXIF_FRAMES - buffer
@@ -724,6 +725,35 @@ ssize_t exif_read (struct file * file, char * buf, size_t count, loff_t *of
	return count;
	return count;
}
}


/* This code is copied from exif_read, consider replacing it with this function invocation */
size_t exif_get_data(int sensor_port, unsigned short meta_index, void *buff, size_t buff_sz)
{
	size_t ret = 0;
	size_t count = exif_template_size;
	loff_t off;
	int start_p, page_p, i;
	char *metap;

	//will truncate by the end of current page
	if (!aexif_enabled[sensor_port])
		return 0;
	off = meta_index * exif_template_size;
	D(printk("%s: count= 0x%x, *off= 0x%x, i=0x%x, exif_template_size=0x%x\n", __func__, (int) count, (int) off, (int) meta_index, (int) exif_template_size));
	start_p = meta_index * exif_template_size;
	page_p = off - start_p;
	D(printk("%s: count= 0x%x, pos= 0x%x, start_p=0x%x, page_p=0x%x, i=0x%x, exif_template_size=0x%x\n", __func__, (int) count, (int) off, (int)start_p, (int)page_p,(int) meta_index, (int) exif_template_size));
	metap = &ameta_buffer[sensor_port][meta_index * aexif_meta_size[sensor_port]]; // pointer to the start of the selected page in frame meta_buffer
	if ((page_p + count) > exif_template_size)
		count = exif_template_size - page_p;
	memcpy(exif_tmp_buff, exif_template, exif_template_size);
	D(printk("%s: count= 0x%x, pos= 0x%x, start_p=0x%x, page_p=0x%x\n", __func__, (int) count, (int) off, (int)start_p, (int)page_p));
	for (i = 0; i < exif_fields; i++) {
		memcpy(&exif_tmp_buff[dir_table[i].dst], &metap[dir_table[i].src], dir_table[i].len);
	}
	memcpy(buff, &exif_tmp_buff[page_p], count);
	return count;
}
EXPORT_SYMBOL_GPL(exif_get_data);


//!++++++++++++++++++++++++++++++++++++ _init() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
//!++++++++++++++++++++++++++++++++++++ _init() ++++++++++++++++++++++++++++++++++++++++++++++++++++++


Loading