提交 5f3cc447 编写于 作者: S Sylwester Nawrocki 提交者: Mauro Carvalho Chehab

[media] s5p-fimc: Add camera capture support

Add a video device driver per each FIMC entity to support
the camera capture input mode. Video capture node is registered
only if CCD sensor data is provided through driver's platfrom data
and board setup code.
Signed-off-by: NSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: NKyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: NMarek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 28f06ff4
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
s5p-fimc-y := fimc-core.o fimc-reg.o
s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
此差异已折叠。
......@@ -11,10 +11,14 @@
#ifndef FIMC_CORE_H_
#define FIMC_CORE_H_
/*#define DEBUG*/
#include <linux/types.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-mediabus.h>
#include <media/s3c_fimc.h>
#include <linux/videodev2.h>
#include "regs-fimc.h"
......@@ -28,6 +32,8 @@
#define dbg(fmt, args...)
#endif
/* Time to wait for next frame VSYNC interrupt while stopping operation. */
#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
#define NUM_FIMC_CLOCKS 2
#define MODULE_NAME "s5p-fimc"
#define FIMC_MAX_DEVS 3
......@@ -36,19 +42,41 @@
#define SCALER_MAX_VRATIO 64
#define DMA_MIN_SIZE 8
enum {
/* FIMC device state flags */
enum fimc_dev_flags {
/* for m2m node */
ST_IDLE,
ST_OUTDMA_RUN,
ST_M2M_PEND,
/* for capture node */
ST_CAPT_PEND,
ST_CAPT_RUN,
ST_CAPT_STREAM,
ST_CAPT_SHUT,
};
#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state)
#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
#define fimc_capture_active(dev) \
(test_bit(ST_CAPT_RUN, &(dev)->state) || \
test_bit(ST_CAPT_PEND, &(dev)->state))
#define fimc_capture_streaming(dev) \
test_bit(ST_CAPT_STREAM, &(dev)->state)
#define fimc_buf_finish(dev, vid_buf) do { \
spin_lock(&(dev)->irqlock); \
(vid_buf)->vb.state = VIDEOBUF_DONE; \
spin_unlock(&(dev)->irqlock); \
wake_up(&(vid_buf)->vb.done); \
} while (0)
enum fimc_datapath {
FIMC_ITU_CAM_A,
FIMC_ITU_CAM_B,
FIMC_MIPI_CAM,
FIMC_CAMERA,
FIMC_DMA,
FIMC_LCDFIFO,
FIMC_WRITEBACK
......@@ -123,20 +151,25 @@ enum fimc_color_fmt {
/**
* struct fimc_fmt - the driver's internal color format data
* @mbus_code: Media Bus pixel code, -1 if not applicable
* @name: format description
* @fourcc: the fourcc code for this format
* @fourcc: the fourcc code for this format, 0 if not applicable
* @color: the corresponding fimc_color_fmt
* @depth: number of bits per pixel
* @depth: driver's private 'number of bits per pixel'
* @buff_cnt: number of physically non-contiguous data planes
* @planes_cnt: number of physically contiguous data planes
*/
struct fimc_fmt {
enum v4l2_mbus_pixelcode mbus_code;
char *name;
u32 fourcc;
u32 color;
u32 depth;
u16 buff_cnt;
u16 planes_cnt;
u16 depth;
u16 flags;
#define FMT_FLAGS_CAM (1 << 0)
#define FMT_FLAGS_M2M (1 << 1)
};
/**
......@@ -220,10 +253,14 @@ struct fimc_addr {
/**
* struct fimc_vid_buffer - the driver's video buffer
* @vb: v4l videobuf buffer
* @vb: v4l videobuf buffer
* @paddr: precalculated physical address set
* @index: buffer index for the output DMA engine
*/
struct fimc_vid_buffer {
struct videobuf_buffer vb;
struct fimc_addr paddr;
int index;
};
/**
......@@ -273,6 +310,40 @@ struct fimc_m2m_device {
int refcnt;
};
/**
* struct fimc_vid_cap - camera capture device information
* @ctx: hardware context data
* @vfd: video device node for camera capture mode
* @v4l2_dev: v4l2_device struct to manage subdevs
* @sd: pointer to camera sensor subdevice currently in use
* @fmt: Media Bus format configured at selected image sensor
* @pending_buf_q: the pending buffer queue head
* @active_buf_q: the queue head of buffers scheduled in hardware
* @vbq: the capture am video buffer queue
* @active_buf_cnt: number of video buffers scheduled in hardware
* @buf_index: index for managing the output DMA buffers
* @frame_count: the frame counter for statistics
* @reqbufs_count: the number of buffers requested in REQBUFS ioctl
* @input_index: input (camera sensor) index
* @refcnt: driver's private reference counter
*/
struct fimc_vid_cap {
struct fimc_ctx *ctx;
struct video_device *vfd;
struct v4l2_device v4l2_dev;
struct v4l2_subdev *sd;
struct v4l2_mbus_framefmt fmt;
struct list_head pending_buf_q;
struct list_head active_buf_q;
struct videobuf_queue vbq;
int active_buf_cnt;
int buf_index;
unsigned int frame_count;
unsigned int reqbufs_count;
int input_index;
int refcnt;
};
/**
* struct samsung_fimc_variant - camera interface variant information
*
......@@ -308,10 +379,12 @@ struct samsung_fimc_variant {
*
* @variant: the variant information for this driver.
* @dev_cnt: number of fimc sub-devices available in SoC
* @lclk_frequency: fimc bus clock frequency
*/
struct samsung_fimc_driverdata {
struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
int devs_cnt;
unsigned long lclk_frequency;
int devs_cnt;
};
struct fimc_ctx;
......@@ -322,19 +395,23 @@ struct fimc_ctx;
* @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device
* @pdata: pointer to the device platform data
* @id: FIMC device index (0..2)
* @clock[]: the clocks required for FIMC operation
* @regs: the mapped hardware registers
* @regs_res: the resource claimed for IO registers
* @irq: interrupt number of the FIMC subdevice
* @irqlock: spinlock protecting videobuffer queue
* @irq_queue:
* @m2m: memory-to-memory V4L2 device information
* @state: the FIMC device state flags
* @vid_cap: camera capture device information
* @state: flags used to synchronize m2m and capture mode operation
*/
struct fimc_dev {
spinlock_t slock;
struct mutex lock;
struct platform_device *pdev;
struct s3c_platform_fimc *pdata;
struct samsung_fimc_variant *variant;
int id;
struct clk *clock[NUM_FIMC_CLOCKS];
......@@ -342,7 +419,9 @@ struct fimc_dev {
struct resource *regs_res;
int irq;
spinlock_t irqlock;
wait_queue_head_t irq_queue;
struct fimc_m2m_device m2m;
struct fimc_vid_cap vid_cap;
unsigned long state;
};
......@@ -387,6 +466,7 @@ struct fimc_ctx {
struct v4l2_m2m_ctx *m2m_ctx;
};
extern struct videobuf_queue_ops fimc_qops;
static inline int tiled_fmt(struct fimc_fmt *fmt)
{
......@@ -433,7 +513,10 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
struct fimc_frame *frame;
if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
frame = &ctx->s_frame;
if (ctx->state & FIMC_CTX_M2M)
frame = &ctx->s_frame;
else
return ERR_PTR(-EINVAL);
} else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
frame = &ctx->d_frame;
} else {
......@@ -445,6 +528,13 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
return frame;
}
static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
{
u32 reg = readl(dev->regs + S5P_CISTATUS);
return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
S5P_CISTATUS_FRAMECNT_SHIFT;
}
/* -----------------------------------------------------*/
/* fimc-reg.c */
void fimc_hw_reset(struct fimc_dev *fimc);
......@@ -462,6 +552,52 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx);
void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
int index);
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam);
int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam);
int fimc_hw_set_camera_type(struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam);
/* -----------------------------------------------------*/
/* fimc-core.c */
int fimc_vidioc_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *f);
int fimc_vidioc_g_fmt(struct file *file, void *priv,
struct v4l2_format *f);
int fimc_vidioc_try_fmt(struct file *file, void *priv,
struct v4l2_format *f);
int fimc_vidioc_g_crop(struct file *file, void *fh,
struct v4l2_crop *cr);
int fimc_vidioc_cropcap(struct file *file, void *fh,
struct v4l2_cropcap *cr);
int fimc_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc);
int fimc_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl);
int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
unsigned int mask);
int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f);
int fimc_set_scaler_info(struct fimc_ctx *ctx);
int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
struct fimc_frame *frame, struct fimc_addr *paddr);
/* -----------------------------------------------------*/
/* fimc-capture.c */
int fimc_register_capture_device(struct fimc_dev *fimc);
void fimc_unregister_capture_device(struct fimc_dev *fimc);
int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
struct fimc_vid_buffer *fimc_vb);
/* Locking: the caller holds fimc->slock */
static inline void fimc_activate_capture(struct fimc_ctx *ctx)
......@@ -478,4 +614,51 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
fimc_hw_en_lastirq(fimc, false);
}
/*
* Add video buffer to the active buffers queue.
* The caller holds irqlock spinlock.
*/
static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
struct fimc_vid_buffer *buf)
{
buf->vb.state = VIDEOBUF_ACTIVE;
list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q);
vid_cap->active_buf_cnt++;
}
/*
* Pop a video buffer from the capture active buffers queue
* Locking: Need to be called with dev->slock held.
*/
static inline struct fimc_vid_buffer *
active_queue_pop(struct fimc_vid_cap *vid_cap)
{
struct fimc_vid_buffer *buf;
buf = list_entry(vid_cap->active_buf_q.next,
struct fimc_vid_buffer, vb.queue);
list_del(&buf->vb.queue);
vid_cap->active_buf_cnt--;
return buf;
}
/* Add video buffer to the capture pending buffers queue */
static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
struct fimc_vid_buffer *buf)
{
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q);
}
/* Add video buffer to the capture pending buffers queue */
static inline struct fimc_vid_buffer *
pending_queue_pop(struct fimc_vid_cap *vid_cap)
{
struct fimc_vid_buffer *buf;
buf = list_entry(vid_cap->pending_buf_q.next,
struct fimc_vid_buffer, vb.queue);
list_del(&buf->vb.queue);
return buf;
}
#endif /* FIMC_CORE_H_ */
......@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <mach/map.h>
#include <media/s3c_fimc.h>
#include "fimc-core.h"
......@@ -176,6 +177,15 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
writel(cfg, dev->regs + S5P_ORGOSIZE);
/* Select color space conversion equation (HD/SD size).*/
cfg = readl(dev->regs + S5P_CIGCTRL);
if (frame->f_width >= 1280) /* HD */
cfg |= S5P_CIGCTRL_CSC_ITU601_709;
else /* SD */
cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
writel(cfg, dev->regs + S5P_CIGCTRL);
}
void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
......@@ -231,19 +241,12 @@ static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
{
unsigned long flags;
u32 cfg;
spin_lock_irqsave(&dev->slock, flags);
cfg = readl(dev->regs + S5P_CIOCTRL);
u32 cfg = readl(dev->regs + S5P_CIOCTRL);
if (enable)
cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
else
cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
writel(cfg, dev->regs + S5P_CIOCTRL);
spin_unlock_irqrestore(&dev->slock, flags);
}
static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
......@@ -325,14 +328,18 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
void fimc_hw_en_capture(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
u32 cfg;
cfg = readl(dev->regs + S5P_CIIMGCPT);
/* One shot mode for output DMA or freerun for FIFO. */
if (ctx->out_path == FIMC_DMA)
cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE;
else
cfg &= ~S5P_CIIMGCPT_CPT_FREN_ENABLE;
u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
if (ctx->out_path == FIMC_DMA) {
/* one shot mode */
cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
} else {
/* Continous frame capture mode (freerun). */
cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
S5P_CIIMGCPT_CPT_FRMOD_CNT);
cfg |= S5P_CIIMGCPT_IMGCPTEN;
}
if (ctx->scaler.enabled)
cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
......@@ -523,3 +530,139 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
i, paddr->y, paddr->cb, paddr->cr);
} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
}
int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam)
{
u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
if (cam->flags & FIMC_CLK_INV_PCLK)
cfg |= S5P_CIGCTRL_INVPOLPCLK;
if (cam->flags & FIMC_CLK_INV_VSYNC)
cfg |= S5P_CIGCTRL_INVPOLVSYNC;
if (cam->flags & FIMC_CLK_INV_HREF)
cfg |= S5P_CIGCTRL_INVPOLHREF;
if (cam->flags & FIMC_CLK_INV_HSYNC)
cfg |= S5P_CIGCTRL_INVPOLHSYNC;
writel(cfg, fimc->regs + S5P_CIGCTRL);
return 0;
}
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam)
{
struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
u32 cfg = 0;
if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
switch (fimc->vid_cap.fmt.code) {
case V4L2_MBUS_FMT_YUYV8_2X8:
cfg = S5P_CISRCFMT_ORDER422_YCBYCR;
break;
case V4L2_MBUS_FMT_YVYU8_2X8:
cfg = S5P_CISRCFMT_ORDER422_YCRYCB;
break;
case V4L2_MBUS_FMT_VYUY8_2X8:
cfg = S5P_CISRCFMT_ORDER422_CRYCBY;
break;
case V4L2_MBUS_FMT_UYVY8_2X8:
cfg = S5P_CISRCFMT_ORDER422_CBYCRY;
break;
default:
err("camera image format not supported: %d",
fimc->vid_cap.fmt.code);
return -EINVAL;
}
if (cam->bus_type == FIMC_ITU_601) {
if (cam->bus_width == 8) {
cfg |= S5P_CISRCFMT_ITU601_8BIT;
} else if (cam->bus_width == 16) {
cfg |= S5P_CISRCFMT_ITU601_16BIT;
} else {
err("invalid bus width: %d", cam->bus_width);
return -EINVAL;
}
} /* else defaults to ITU-R BT.656 8-bit */
}
cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
writel(cfg, fimc->regs + S5P_CISRCFMT);
return 0;
}
int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
{
u32 hoff2, voff2;
u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
cfg |= S5P_CIWDOFST_OFF_EN |
S5P_CIWDOFST_HOROFF(f->offs_h) |
S5P_CIWDOFST_VEROFF(f->offs_v);
writel(cfg, fimc->regs + S5P_CIWDOFST);
/* See CIWDOFSTn register description in the datasheet for details. */
hoff2 = f->o_width - f->width - f->offs_h;
voff2 = f->o_height - f->height - f->offs_v;
cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
writel(cfg, fimc->regs + S5P_CIWDOFST2);
return 0;
}
int fimc_hw_set_camera_type(struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam)
{
u32 cfg, tmp;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
cfg = readl(fimc->regs + S5P_CIGCTRL);
/* Select ITU B interface, disable Writeback path and test pattern. */
cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
S5P_CIGCTRL_SELCAM_MIPI_A);
if (cam->bus_type == FIMC_MIPI_CSI2) {
cfg |= S5P_CIGCTRL_SELCAM_MIPI;
if (cam->mux_id == 0)
cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
/* TODO: add remaining supported formats. */
if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
} else {
err("camera image format not supported: %d",
vid_cap->fmt.code);
return -EINVAL;
}
writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT);
} else if (cam->bus_type == FIMC_ITU_601 ||
cam->bus_type == FIMC_ITU_656) {
if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
} else if (cam->bus_type == FIMC_LCD_WB) {
cfg |= S5P_CIGCTRL_CAMIF_SELWB;
} else {
err("invalid camera bus type selected\n");
return -EINVAL;
}
writel(cfg, fimc->regs + S5P_CIGCTRL);
return 0;
}
/*
* Samsung S5P SoC camera interface driver header
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd
* Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef S3C_FIMC_H_
#define S3C_FIMC_H_
enum cam_bus_type {
FIMC_ITU_601 = 1,
FIMC_ITU_656,
FIMC_MIPI_CSI2,
FIMC_LCD_WB, /* FIFO link from LCD mixer */
};
#define FIMC_CLK_INV_PCLK (1 << 0)
#define FIMC_CLK_INV_VSYNC (1 << 1)
#define FIMC_CLK_INV_HREF (1 << 2)
#define FIMC_CLK_INV_HSYNC (1 << 3)
struct i2c_board_info;
/**
* struct s3c_fimc_isp_info - image sensor information required for host
* interace configuration.
*
* @board_info: pointer to I2C subdevice's board info
* @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
* @i2c_bus_num: i2c control bus id the sensor is attached to
* @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
* @bus_width: camera data bus width in bits
* @flags: flags defining bus signals polarity inversion (High by default)
*/
struct s3c_fimc_isp_info {
struct i2c_board_info *board_info;
enum cam_bus_type bus_type;
u16 i2c_bus_num;
u16 mux_id;
u16 bus_width;
u16 flags;
};
#define FIMC_MAX_CAMIF_CLIENTS 2
/**
* struct s3c_platform_fimc - camera host interface platform data
*
* @isp_info: properties of camera sensor required for host interface setup
*/
struct s3c_platform_fimc {
struct s3c_fimc_isp_info *isp_info[FIMC_MAX_CAMIF_CLIENTS];
};
#endif /* S3C_FIMC_H_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册