alistair23-linux/drivers/staging/dream/camera/msm_v4l2.c
Tejun Heo 5a0e3ad6af include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.

percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.

  http://userweb.kernel.org/~tj/misc/slabh-sweep.py

The script does the followings.

* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.

* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.

* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.

The conversion was done in the following steps.

1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.

2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.

3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.

4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.

5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.

6. percpu.h was updated not to include slab.h.

7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).

   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig

8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.

Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.

Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-30 22:02:32 +09:00

799 lines
18 KiB
C

/*
*
* Copyright (C) 2008-2009 QUALCOMM Incorporated.
*
*/
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/ioctl.h>
#include <linux/spinlock.h>
#include <linux/videodev2.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <media/v4l2-dev.h>
#include <media/msm_camera.h>
#include <mach/camera.h>
#include <media/v4l2-ioctl.h>
/*#include <linux/platform_device.h>*/
#define MSM_V4L2_START_SNAPSHOT _IOWR('V', BASE_VIDIOC_PRIVATE+1, \
struct v4l2_buffer)
#define MSM_V4L2_GET_PICTURE _IOWR('V', BASE_VIDIOC_PRIVATE+2, \
struct v4l2_buffer)
#define MSM_V4L2_DEVICE_NAME "msm_v4l2"
#define MSM_V4L2_PROC_NAME "msm_v4l2"
#define MSM_V4L2_DEVNUM_MPEG2 0
#define MSM_V4L2_DEVNUM_YUV 20
/* HVGA-P (portrait) and HVGA-L (landscape) */
#define MSM_V4L2_WIDTH 480
#define MSM_V4L2_HEIGHT 320
#if 1
#define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args)
#else
#define D(fmt, args...) do {} while (0)
#endif
#define PREVIEW_FRAMES_NUM 4
struct msm_v4l2_device {
struct list_head read_queue;
struct v4l2_format current_cap_format;
struct v4l2_format current_pix_format;
struct video_device *pvdev;
struct msm_v4l2_driver *drv;
uint8_t opencnt;
spinlock_t read_queue_lock;
};
static struct msm_v4l2_device *g_pmsm_v4l2_dev;
static DEFINE_MUTEX(msm_v4l2_opencnt_lock);
static int msm_v4l2_open(struct file *f)
{
int rc = 0;
D("%s\n", __func__);
mutex_lock(&msm_v4l2_opencnt_lock);
if (!g_pmsm_v4l2_dev->opencnt) {
rc = g_pmsm_v4l2_dev->drv->open(
g_pmsm_v4l2_dev->drv->sync,
MSM_APPS_ID_V4L2);
}
g_pmsm_v4l2_dev->opencnt++;
mutex_unlock(&msm_v4l2_opencnt_lock);
return rc;
}
static int msm_v4l2_release(struct file *f)
{
int rc = 0;
D("%s\n", __func__);
mutex_lock(&msm_v4l2_opencnt_lock);
if (!g_pmsm_v4l2_dev->opencnt) {
g_pmsm_v4l2_dev->opencnt--;
if (!g_pmsm_v4l2_dev->opencnt) {
rc = g_pmsm_v4l2_dev->drv->release(
g_pmsm_v4l2_dev->drv->sync);
}
}
mutex_unlock(&msm_v4l2_opencnt_lock);
return rc;
}
static unsigned int msm_v4l2_poll(struct file *f, struct poll_table_struct *w)
{
return g_pmsm_v4l2_dev->drv->drv_poll(g_pmsm_v4l2_dev->drv->sync, f, w);
}
static long msm_v4l2_ioctl(struct file *filep,
unsigned int cmd, unsigned long arg)
{
struct msm_ctrl_cmd *ctrlcmd;
D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd, __LINE__);
switch (cmd) {
case MSM_V4L2_START_SNAPSHOT:
ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
if (!ctrlcmd) {
CDBG("msm_v4l2_ioctl: cannot allocate buffer\n");
return -ENOMEM;
}
ctrlcmd->length = 0;
ctrlcmd->value = NULL;
ctrlcmd->timeout_ms = 10000;
D("msm_v4l2_ioctl, MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n",
cmd);
ctrlcmd->type = MSM_V4L2_SNAPSHOT;
return g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync,
ctrlcmd);
case MSM_V4L2_GET_PICTURE:
D("msm_v4l2_ioctl, MSM_V4L2_GET_PICTURE v4l2 ioctl %d\n", cmd);
ctrlcmd = (struct msm_ctrl_cmd *)arg;
return g_pmsm_v4l2_dev->drv->get_pict(
g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
default:
D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd);
return video_ioctl2(filep, cmd, arg);
}
}
static void msm_v4l2_release_dev(struct video_device *d)
{
D("%s\n", __func__);
}
static int msm_v4l2_querycap(struct file *f,
void *pctx, struct v4l2_capability *pcaps)
{
D("%s\n", __func__);
strncpy(pcaps->driver, MSM_APPS_ID_V4L2, sizeof(pcaps->driver));
strncpy(pcaps->card,
MSM_V4L2_DEVICE_NAME, sizeof(pcaps->card));
pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
return 0;
}
static int msm_v4l2_s_std(struct file *f, void *pctx, v4l2_std_id *pnorm)
{
D("%s\n", __func__);
return 0;
}
static int msm_v4l2_queryctrl(struct file *f,
void *pctx, struct v4l2_queryctrl *pqctrl)
{
int rc = 0;
struct msm_ctrl_cmd *ctrlcmd;
D("%s\n", __func__);
ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
if (!ctrlcmd) {
CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n");
return -ENOMEM;
}
ctrlcmd->type = MSM_V4L2_QUERY_CTRL;
ctrlcmd->length = sizeof(struct v4l2_queryctrl);
ctrlcmd->value = pqctrl;
ctrlcmd->timeout_ms = 10000;
rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
if (rc < 0)
return -1;
return ctrlcmd->status;
}
static int msm_v4l2_g_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
{
int rc = 0;
struct msm_ctrl_cmd *ctrlcmd;
D("%s\n", __func__);
ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
if (!ctrlcmd) {
CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n");
return -ENOMEM;
}
ctrlcmd->type = MSM_V4L2_GET_CTRL;
ctrlcmd->length = sizeof(struct v4l2_control);
ctrlcmd->value = c;
ctrlcmd->timeout_ms = 10000;
rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
if (rc < 0)
return -1;
return ctrlcmd->status;
}
static int msm_v4l2_s_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
{
int rc = 0;
struct msm_ctrl_cmd *ctrlcmd;
ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
if (!ctrlcmd) {
CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n");
return -ENOMEM;
}
ctrlcmd->type = MSM_V4L2_SET_CTRL;
ctrlcmd->length = sizeof(struct v4l2_control);
ctrlcmd->value = c;
ctrlcmd->timeout_ms = 10000;
D("%s\n", __func__);
rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
if (rc < 0)
return -1;
return ctrlcmd->status;
}
static int msm_v4l2_reqbufs(struct file *f,
void *pctx, struct v4l2_requestbuffers *b)
{
D("%s\n", __func__);
return 0;
}
static int msm_v4l2_querybuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
{
struct msm_pmem_info pmem_buf;
#if 0
__u32 width = 0;
__u32 height = 0;
__u32 y_size = 0;
__u32 y_pad = 0;
/* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.width; */
width = 640;
/* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.height; */
height = 480;
D("%s: width = %d, height = %d\n", __func__, width, height);
y_size = width * height;
y_pad = y_size % 4;
#endif
__u32 y_pad = pb->bytesused % 4;
/* V4L2 videodev will do the copy_from_user. */
memset(&pmem_buf, 0, sizeof(struct msm_pmem_info));
pmem_buf.type = MSM_PMEM_OUTPUT2;
pmem_buf.vaddr = (void *)pb->m.userptr;
pmem_buf.y_off = 0;
pmem_buf.fd = (int)pb->reserved;
/* pmem_buf.cbcr_off = (y_size + y_pad); */
pmem_buf.cbcr_off = (pb->bytesused + y_pad);
g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, &pmem_buf);
return 0;
}
static int msm_v4l2_qbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
{
/*
__u32 y_size = 0;
__u32 y_pad = 0;
__u32 width = 0;
__u32 height = 0;
*/
__u32 y_pad = 0;
struct msm_pmem_info meminfo;
struct msm_frame frame;
static int cnt;
if ((pb->flags >> 16) & 0x0001) {
/* this is for previwe */
#if 0
width = 640;
height = 480;
/* V4L2 videodev will do the copy_from_user. */
D("%s: width = %d, height = %d\n", __func__, width, height);
y_size = width * height;
y_pad = y_size % 4;
#endif
y_pad = pb->bytesused % 4;
if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
/* this qbuf is actually for releasing */
frame.buffer = pb->m.userptr;
frame.y_off = 0;
/* frame.cbcr_off = (y_size + y_pad); */
frame.cbcr_off = (pb->bytesused + y_pad);
frame.fd = pb->reserved;
D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n",
pb->bytesused);
g_pmsm_v4l2_dev->drv->put_frame(
g_pmsm_v4l2_dev->drv->sync,
&frame);
return 0;
}
D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n",
pb->bytesused);
meminfo.type = MSM_PMEM_OUTPUT2;
meminfo.fd = (int)pb->reserved;
meminfo.vaddr = (void *)pb->m.userptr;
meminfo.y_off = 0;
/* meminfo.cbcr_off = (y_size + y_pad); */
meminfo.cbcr_off = (pb->bytesused + y_pad);
if (cnt == PREVIEW_FRAMES_NUM - 1)
meminfo.active = 0;
else
meminfo.active = 1;
cnt++;
g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
&meminfo);
} else if ((pb->flags) & 0x0001) {
/* this is for snapshot */
__u32 y_size = 0;
if ((pb->flags >> 8) & 0x01) {
y_size = pb->bytesused;
meminfo.type = MSM_PMEM_THUMBAIL;
} else if ((pb->flags >> 9) & 0x01) {
y_size = pb->bytesused;
meminfo.type = MSM_PMEM_MAINIMG;
}
y_pad = y_size % 4;
meminfo.fd = (int)pb->reserved;
meminfo.vaddr = (void *)pb->m.userptr;
meminfo.y_off = 0;
/* meminfo.cbcr_off = (y_size + y_pad); */
meminfo.cbcr_off = (y_size + y_pad);
meminfo.active = 1;
g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
&meminfo);
}
return 0;
}
static int msm_v4l2_dqbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
{
struct msm_frame frame;
D("%s\n", __func__);
/* V4L2 videodev will do the copy_to_user. */
if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
D("%s, %d\n", __func__, __LINE__);
g_pmsm_v4l2_dev->drv->get_frame(
g_pmsm_v4l2_dev->drv->sync,
&frame);
pb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pb->m.userptr = (unsigned long)frame.buffer; /* FIXME */
pb->reserved = (int)frame.fd;
/* pb->length = (int)frame.cbcr_off; */
pb->bytesused = frame.cbcr_off;
} else if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
__u32 y_pad = pb->bytesused % 4;
frame.buffer = pb->m.userptr;
frame.y_off = 0;
/* frame.cbcr_off = (y_size + y_pad); */
frame.cbcr_off = (pb->bytesused + y_pad);
frame.fd = pb->reserved;
g_pmsm_v4l2_dev->drv->put_frame(
g_pmsm_v4l2_dev->drv->sync,
&frame);
}
return 0;
}
static int msm_v4l2_streamon(struct file *f, void *pctx, enum v4l2_buf_type i)
{
struct msm_ctrl_cmd *ctrlcmd;
ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
if (!ctrlcmd) {
CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
return -ENOMEM;
}
ctrlcmd->type = MSM_V4L2_STREAM_ON;
ctrlcmd->timeout_ms = 10000;
ctrlcmd->length = 0;
ctrlcmd->value = NULL;
D("%s\n", __func__);
g_pmsm_v4l2_dev->drv->ctrl(
g_pmsm_v4l2_dev->drv->sync,
ctrlcmd);
D("%s after drv->ctrl \n", __func__);
return 0;
}
static int msm_v4l2_streamoff(struct file *f, void *pctx, enum v4l2_buf_type i)
{
struct msm_ctrl_cmd *ctrlcmd;
ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
if (!ctrlcmd) {
CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
return -ENOMEM;
}
ctrlcmd->type = MSM_V4L2_STREAM_OFF;
ctrlcmd->timeout_ms = 10000;
ctrlcmd->length = 0;
ctrlcmd->value = NULL;
D("%s\n", __func__);
g_pmsm_v4l2_dev->drv->ctrl(
g_pmsm_v4l2_dev->drv->sync,
ctrlcmd);
return 0;
}
static int msm_v4l2_enum_fmt_overlay(struct file *f,
void *pctx, struct v4l2_fmtdesc *pfmtdesc)
{
D("%s\n", __func__);
return 0;
}
static int msm_v4l2_enum_fmt_cap(struct file *f,
void *pctx, struct v4l2_fmtdesc *pfmtdesc)
{
D("%s\n", __func__);
switch (pfmtdesc->index) {
case 0:
pfmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pfmtdesc->flags = 0;
strncpy(pfmtdesc->description, "YUV 4:2:0",
sizeof(pfmtdesc->description));
pfmtdesc->pixelformat = V4L2_PIX_FMT_YVU420;
break;
default:
return -EINVAL;
}
return 0;
}
static int msm_v4l2_g_fmt_cap(struct file *f,
void *pctx, struct v4l2_format *pfmt)
{
D("%s\n", __func__);
pfmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pfmt->fmt.pix.width = MSM_V4L2_WIDTH;
pfmt->fmt.pix.height = MSM_V4L2_HEIGHT;
pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
pfmt->fmt.pix.field = V4L2_FIELD_ANY;
pfmt->fmt.pix.bytesperline = 0;
pfmt->fmt.pix.sizeimage = 0;
pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
pfmt->fmt.pix.priv = 0;
return 0;
}
static int msm_v4l2_s_fmt_cap(struct file *f,
void *pctx, struct v4l2_format *pfmt)
{
struct msm_ctrl_cmd *ctrlcmd;
D("%s\n", __func__);
ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
if (!ctrlcmd) {
CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
return -ENOMEM;
}
ctrlcmd->type = MSM_V4L2_VID_CAP_TYPE;
ctrlcmd->length = sizeof(struct v4l2_format);
ctrlcmd->value = pfmt;
ctrlcmd->timeout_ms = 10000;
if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
kfree(ctrlcmd);
return -1;
}
#if 0
/* FIXEME */
if (pfmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YVU420) {
kfree(ctrlcmd);
return -EINVAL;
}
#endif
/* Ok, but check other params, too. */
#if 0
memcpy(&g_pmsm_v4l2_dev->current_pix_format.fmt.pix, pfmt,
sizeof(struct v4l2_format));
#endif
g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
return 0;
}
static int msm_v4l2_g_fmt_overlay(struct file *f,
void *pctx, struct v4l2_format *pfmt)
{
D("%s\n", __func__);
pfmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
pfmt->fmt.pix.width = MSM_V4L2_WIDTH;
pfmt->fmt.pix.height = MSM_V4L2_HEIGHT;
pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
pfmt->fmt.pix.field = V4L2_FIELD_ANY;
pfmt->fmt.pix.bytesperline = 0;
pfmt->fmt.pix.sizeimage = 0;
pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
pfmt->fmt.pix.priv = 0;
return 0;
}
static int msm_v4l2_s_fmt_overlay(struct file *f,
void *pctx, struct v4l2_format *pfmt)
{
D("%s\n", __func__);
return 0;
}
static int msm_v4l2_overlay(struct file *f, void *pctx, unsigned int i)
{
D("%s\n", __func__);
return 0;
}
static int msm_v4l2_g_jpegcomp(struct file *f,
void *pctx, struct v4l2_jpegcompression *pcomp)
{
D("%s\n", __func__);
return 0;
}
static int msm_v4l2_s_jpegcomp(struct file *f,
void *pctx, struct v4l2_jpegcompression *pcomp)
{
D("%s\n", __func__);
return 0;
}
#ifdef CONFIG_PROC_FS
int msm_v4l2_read_proc(char *pbuf, char **start, off_t offset,
int count, int *eof, void *data)
{
int len = 0;
len += snprintf(pbuf, strlen("stats\n") + 1, "stats\n");
if (g_pmsm_v4l2_dev) {
len += snprintf(pbuf, strlen("mode: ") + 1, "mode: ");
if (g_pmsm_v4l2_dev->current_cap_format.type
== V4L2_BUF_TYPE_VIDEO_CAPTURE)
len += snprintf(pbuf, strlen("capture\n") + 1,
"capture\n");
else
len += snprintf(pbuf, strlen("unknown\n") + 1,
"unknown\n");
len += snprintf(pbuf, 21, "resolution: %dx%d\n",
g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
width,
g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
height);
len += snprintf(pbuf,
strlen("pixel format: ") + 1, "pixel format: ");
if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.pixelformat
== V4L2_PIX_FMT_YVU420)
len += snprintf(pbuf, strlen("yvu420\n") + 1,
"yvu420\n");
else
len += snprintf(pbuf, strlen("unknown\n") + 1,
"unknown\n");
len += snprintf(pbuf, strlen("colorspace: ") + 1,
"colorspace: ");
if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.colorspace
== V4L2_COLORSPACE_JPEG)
len += snprintf(pbuf, strlen("jpeg\n") + 1, "jpeg\n");
else
len += snprintf(pbuf, strlen("unknown\n") + 1,
"unknown\n");
}
*eof = 1;
return len;
}
#endif
static const struct v4l2_file_operations msm_v4l2_fops = {
.owner = THIS_MODULE,
.open = msm_v4l2_open,
.poll = msm_v4l2_poll,
.release = msm_v4l2_release,
.ioctl = msm_v4l2_ioctl,
};
static void msm_v4l2_dev_init(struct msm_v4l2_device *pmsm_v4l2_dev)
{
pmsm_v4l2_dev->read_queue_lock =
__SPIN_LOCK_UNLOCKED(pmsm_v4l2_dev->read_queue_lock);
INIT_LIST_HEAD(&pmsm_v4l2_dev->read_queue);
}
static int msm_v4l2_try_fmt_cap(struct file *file,
void *fh, struct v4l2_format *f)
{
/* FIXME */
return 0;
}
static int mm_v4l2_try_fmt_type_private(struct file *file,
void *fh, struct v4l2_format *f)
{
/* FIXME */
return 0;
}
/*
* should the following structure be used instead of the code in the function?
* static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
* .vidioc_querycap = ....
* }
*/
static const struct v4l2_ioctl_ops msm_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_s_std = msm_v4l2_s_std,
.vidioc_queryctrl = msm_v4l2_queryctrl,
.vidioc_g_ctrl = msm_v4l2_g_ctrl,
.vidioc_s_ctrl = msm_v4l2_s_ctrl,
.vidioc_reqbufs = msm_v4l2_reqbufs,
.vidioc_querybuf = msm_v4l2_querybuf,
.vidioc_qbuf = msm_v4l2_qbuf,
.vidioc_dqbuf = msm_v4l2_dqbuf,
.vidioc_streamon = msm_v4l2_streamon,
.vidioc_streamoff = msm_v4l2_streamoff,
.vidioc_enum_fmt_vid_overlay = msm_v4l2_enum_fmt_overlay,
.vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt_cap,
.vidioc_try_fmt_vid_cap = msm_v4l2_try_fmt_cap,
.vidioc_try_fmt_type_private = mm_v4l2_try_fmt_type_private,
.vidioc_g_fmt_vid_cap = msm_v4l2_g_fmt_cap,
.vidioc_s_fmt_vid_cap = msm_v4l2_s_fmt_cap,
.vidioc_g_fmt_vid_overlay = msm_v4l2_g_fmt_overlay,
.vidioc_s_fmt_vid_overlay = msm_v4l2_s_fmt_overlay,
.vidioc_overlay = msm_v4l2_overlay,
.vidioc_g_jpegcomp = msm_v4l2_g_jpegcomp,
.vidioc_s_jpegcomp = msm_v4l2_s_jpegcomp,
};
static int msm_v4l2_video_dev_init(struct video_device *pvd)
{
strncpy(pvd->name, MSM_APPS_ID_V4L2, sizeof(pvd->name));
pvd->vfl_type = 1;
pvd->fops = &msm_v4l2_fops;
pvd->release = msm_v4l2_release_dev;
pvd->minor = -1;
pvd->ioctl_ops = &msm_ioctl_ops;
return msm_v4l2_register(g_pmsm_v4l2_dev->drv);
}
static int __init msm_v4l2_init(void)
{
int rc = -ENOMEM;
struct video_device *pvdev = NULL;
struct msm_v4l2_device *pmsm_v4l2_dev = NULL;
D("%s\n", __func__);
pvdev = video_device_alloc();
if (pvdev == NULL)
return rc;
pmsm_v4l2_dev =
kzalloc(sizeof(struct msm_v4l2_device), GFP_KERNEL);
if (pmsm_v4l2_dev == NULL) {
video_device_release(pvdev);
return rc;
}
msm_v4l2_dev_init(pmsm_v4l2_dev);
g_pmsm_v4l2_dev = pmsm_v4l2_dev;
g_pmsm_v4l2_dev->pvdev = pvdev;
g_pmsm_v4l2_dev->drv =
kzalloc(sizeof(struct msm_v4l2_driver), GFP_KERNEL);
if (!g_pmsm_v4l2_dev->drv) {
video_device_release(pvdev);
kfree(pmsm_v4l2_dev);
return rc;
}
rc = msm_v4l2_video_dev_init(pvdev);
if (rc < 0) {
video_device_release(pvdev);
kfree(g_pmsm_v4l2_dev->drv);
kfree(pmsm_v4l2_dev);
return rc;
}
if (video_register_device(pvdev, VFL_TYPE_GRABBER,
MSM_V4L2_DEVNUM_YUV)) {
D("failed to register device\n");
video_device_release(pvdev);
kfree(g_pmsm_v4l2_dev);
g_pmsm_v4l2_dev = NULL;
return -ENOENT;
}
#ifdef CONFIG_PROC_FS
create_proc_read_entry(MSM_V4L2_PROC_NAME,
0, NULL, msm_v4l2_read_proc, NULL);
#endif
return 0;
}
static void __exit msm_v4l2_exit(void)
{
struct video_device *pvdev = g_pmsm_v4l2_dev->pvdev;
D("%s\n", __func__);
#ifdef CONFIG_PROC_FS
remove_proc_entry(MSM_V4L2_PROC_NAME, NULL);
#endif
video_unregister_device(pvdev);
video_device_release(pvdev);
msm_v4l2_unregister(g_pmsm_v4l2_dev->drv);
kfree(g_pmsm_v4l2_dev->drv);
g_pmsm_v4l2_dev->drv = NULL;
kfree(g_pmsm_v4l2_dev);
g_pmsm_v4l2_dev = NULL;
}
module_init(msm_v4l2_init);
module_exit(msm_v4l2_exit);
MODULE_DESCRIPTION("MSM V4L2 driver");
MODULE_LICENSE("GPL v2");