SmartAudio/lichee/linux-4.9/drivers/media/platform/sunxi-vfe/sample.c

264 lines
6.1 KiB
C

/*
* linux-4.9/drivers/media/platform/sunxi-vfe/sample.c
*
* Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "vfe.h"
extern int vfe_open_special(int id);
extern int vfe_close_special(int id);
extern int vfe_s_input_special(int id, int sel);
extern int vfe_s_fmt_special(int id, struct v4l2_format *f);
extern int vfe_g_fmt_special(int id, struct v4l2_format *f);
extern int vfe_dqbuffer_special(int id, struct vfe_buffer **buf);
extern int vfe_qbuffer_special(int id, struct vfe_buffer *buf);
extern int vfe_streamon_special(int id, enum v4l2_buf_type i);
extern int vfe_streamoff_special(int id, enum v4l2_buf_type i);
extern void vfe_register_buffer_done_callback(int id, void *func);
extern int os_mem_alloc_sample(int id, struct vfe_mm *mem_man);
extern void os_mem_free_sample(int id, struct vfe_mm *mem_man);
#define BUF_NUM 8
#define ALIGN_4K(x) (((x) + (4095)) & ~(4095))
#define ALIGN_16B(x) (((x) + (15)) & ~(15))
int vfe_id;
int width = 640;
int height = 480;
int frame_cnt;
int save_cnt;
struct work_struct save_work;
struct vfe_mm ion_buf[BUF_NUM];
struct vfe_buffer video_buf[BUF_NUM];
char file_path_isp[100] = "/mnt/fb.yuv";
module_param(width, uint, S_IRUGO | S_IWUSR);
module_param(height, uint, S_IRUGO | S_IWUSR);
module_param(vfe_id, uint, S_IRUGO | S_IWUSR);
module_param(save_cnt, uint, S_IRUGO | S_IWUSR);
module_param_string(file_path_isp, file_path_isp, sizeof(file_path_isp), S_IRUGO | S_IWUSR);
static int file_write(struct file *fp, char *buf, size_t len)
{
mm_segment_t old_fs;
loff_t pos = 0;
int buf_len;
if (IS_ERR_OR_NULL(fp)) {
pr_info("cfg write file error, fp is null!");
return -1;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
buf_len = vfs_write(fp, buf, len, &pos);
set_fs(old_fs);
if (buf_len < 0)
return -1;
if (buf_len != len)
pr_info("buf_len = %x, len = %pa\n", buf_len, &len);
return buf_len;
}
static void sample_save_frame(struct work_struct *work)
{
struct file *fp;
int i, ret;
struct vfe_buffer *vfe_buf;
vfe_dqbuffer_special(vfe_id, &vfe_buf);
fp = filp_open(file_path_isp, O_RDWR | O_APPEND | O_CREAT, 0666);
if (IS_ERR_OR_NULL(fp)) {
pr_info("open %s failed!, ERR NO is %ld.\n", file_path_isp, (long)fp);
goto qbuf;
}
for (i = 0; i < BUF_NUM; ++i) {
if (vfe_buf->paddr == ion_buf[i].dma_addr)
break;
}
ret = file_write(fp, (char *)ion_buf[i].vir_addr, width*height*3/2);
if (ret < 0)
pr_info("file_write failed!, ERR NO is %d.\n", ret);
ret = filp_close(fp, NULL);
if (ret < 0)
pr_info("file close failed!, ERR NO is %d.\n", ret);
qbuf:
vfe_qbuffer_special(vfe_id, vfe_buf);
}
static int sample_req_buffers(void)
{
unsigned int i;
for (i = 0; i < BUF_NUM; ++i) {
ion_buf[i].size = ALIGN_4K(ALIGN_16B(width)*height*3/2);
if (os_mem_alloc_sample(vfe_id, &ion_buf[i]) < 0) {
pr_info("alloc ion buffer failed\n");
return -1;
}
video_buf[i].paddr = ion_buf[i].dma_addr;
if (vfe_qbuffer_special(vfe_id, &video_buf[i])) {
pr_info("vfe_qbuffer_special failed\n");
return -1;
}
}
return 0;
}
static int sample_free_buffers(void)
{
unsigned int i;
struct vfe_buffer *vfe_buf;
for (i = 0; i < BUF_NUM; ++i) {
os_mem_free_sample(vfe_id, &ion_buf[i]);
vfe_dqbuffer_special(vfe_id, &vfe_buf);
}
return 0;
}
static int sample_video_open(int sel)
{
if (vfe_open_special(vfe_id) < 0) {
pr_info("vfe_open_special falied\n");
return -1;
}
if (vfe_s_input_special(vfe_id, 0) < 0) {
pr_info("vfe_s_input_special %d error!\n", sel);
return -1;
}
return 0;
}
static int sample_fmt_set(void)
{
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = width;
fmt.fmt.pix.height = height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (vfe_s_fmt_special(vfe_id, &fmt) < 0) {
pr_info("vfe_s_fmt_special error!\n");
return -1;
}
if (vfe_g_fmt_special(vfe_id, &fmt) < 0) {
pr_info("vfe_g_fmt_special error!\n");
return -1;
} else {
pr_info("resolution got from sensor = %d*%d\n",
fmt.fmt.pix.width, fmt.fmt.pix.height);
}
return 0;
}
void sample_buffer_process(int id)
{
struct vfe_buffer *vfe_buf;
frame_cnt++;
if (frame_cnt <= save_cnt) {
pr_info("save frame %d\n", frame_cnt);
schedule_work(&save_work);
} else {
vfe_dqbuffer_special(vfe_id, &vfe_buf);
pr_info("csi %d buffer process\n", id);
vfe_qbuffer_special(vfe_id, vfe_buf);
}
}
int sample_start(void)
{
if (-1 == sample_video_open(0))
return -1;
if (-1 == sample_fmt_set())
return -1;
if (-1 == sample_req_buffers())
return -1;
vfe_register_buffer_done_callback(vfe_id, sample_buffer_process);
frame_cnt = 0;
if (vfe_streamon_special(vfe_id, V4L2_BUF_TYPE_VIDEO_CAPTURE) < 0) {
pr_info("vfe_streamon_special failed\n");
return -1;
} else {
pr_info("vfe_streamon_special ok\n");
}
return 0;
}
int sample_end(void)
{
if (vfe_streamoff_special(vfe_id, V4L2_BUF_TYPE_VIDEO_CAPTURE) < 0) {
pr_info("vfe_streamoff_special failed\n");
return -1;
} else {
pr_info("vfe_streamoff_special ok\n");
}
if (-1 == sample_free_buffers())
return -1;
if (vfe_close_special(vfe_id) < 0) {
pr_info("vfe_close_special falied\n");
return -1;
}
return 0;
}
static int __init sample_init(void)
{
INIT_WORK(&save_work, sample_save_frame);
return sample_start();
}
static void __exit sample_exit(void)
{
flush_work(&save_work);
sample_end();
}
module_init(sample_init);
module_exit(sample_exit);
MODULE_AUTHOR("zhaowei");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("video kernel api test");