msm: camera: Change camera server into a video node
Convert ioctl and server node to be compliant with
v4l2 architecture.
Add multiple control and event queue to
support multiple camera instance
Change-Id: Idcb8533e15599f7fb0ad621c3da6b19235fa64f4
Signed-off-by: Kevin Chan <ktchan@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 3723da8..2019f9b 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -598,6 +598,11 @@
.sensor_type = BAYER_SENSOR,
};
+static struct platform_device msm_camera_server = {
+ .name = "msm_cam_server",
+ .id = 0,
+};
+
void __init apq8064_init_cam(void)
{
msm_gpiomux_install(apq8064_cam_common_configs,
@@ -609,6 +614,7 @@
} else if (machine_is_apq8064_liquid())
sensor_board_info_imx074.mount_angle = 180;
+ platform_device_register(&msm_camera_server);
platform_device_register(&msm8960_device_i2c_mux_gsbi4);
platform_device_register(&msm8960_device_csiphy0);
platform_device_register(&msm8960_device_csiphy1);
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index d7ad549..e7992f9 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -562,11 +562,17 @@
.sensor_type = BAYER_SENSOR,
};
+static struct platform_device msm_camera_server = {
+ .name = "msm_cam_server",
+ .id = 0,
+};
+
void __init msm8930_init_cam(void)
{
msm_gpiomux_install(msm8930_cam_common_configs,
ARRAY_SIZE(msm8930_cam_common_configs));
+ platform_device_register(&msm_camera_server);
platform_device_register(&msm8960_device_csiphy0);
platform_device_register(&msm8960_device_csiphy1);
platform_device_register(&msm8960_device_csid0);
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 0d1c72d..b60519b 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -681,6 +681,11 @@
return rc;
}
+static struct platform_device msm_camera_server = {
+ .name = "msm_cam_server",
+ .id = 0,
+};
+
void __init msm8960_init_cam(void)
{
msm_gpiomux_install(msm8960_cam_common_configs,
@@ -709,6 +714,7 @@
msm_camera_8960_ext_power_ctrl;
}
+ platform_device_register(&msm_camera_server);
platform_device_register(&msm8960_device_csiphy0);
platform_device_register(&msm8960_device_csiphy1);
platform_device_register(&msm8960_device_csiphy2);
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index f7333b9..9d01d90 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -276,6 +276,11 @@
};
#endif
+static struct platform_device msm_camera_server = {
+ .name = "msm_cam_server",
+ .id = 0,
+};
+
static void __init msm7x27a_init_cam(void)
{
if (!(machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
@@ -291,6 +296,7 @@
sensor_board_info_ov5647.cam_vreg = NULL;
sensor_board_info_ov5647.num_vreg = 0;
}
+ platform_device_register(&msm_camera_server);
if (machine_is_msm8625_surf() || machine_is_msm8625_evb()) {
platform_device_register(&msm8625_device_csic0);
platform_device_register(&msm8625_device_csic1);
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 6bc21bb..7fa4968 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -993,8 +993,14 @@
.camera_type = BACK_CAMERA_2D,
};
+static struct platform_device msm_camera_server = {
+ .name = "msm_cam_server",
+ .id = 0,
+};
+
void __init msm7x30_init_cam(void)
{
+ platform_device_register(&msm_camera_server);
platform_device_register(&msm_device_csic0);
platform_device_register(&msm_device_vfe);
platform_device_register(&msm_device_vpe);
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index 9b3d9eb..743ca4d 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -448,8 +448,14 @@
.actuator_info = &imx074_actuator_info
};
+static struct platform_device msm_camera_server = {
+ .name = "msm_cam_server",
+ .id = 0,
+};
+
void __init msm8x60_init_cam(void)
{
+ platform_device_register(&msm_camera_server);
platform_device_register(&msm_device_csic0);
platform_device_register(&msm_device_csic1);
platform_device_register(&msm_device_vfe);
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 04cfa71..7857e69 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -365,6 +365,7 @@
struct list_head list_frame;
struct list_head list_pict;
struct list_head list_vpe_frame;
+ struct list_head list_eventdata;
enum msm_queue type;
void *command;
atomic_t on_heap;
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index da38acc..ff97fa3 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -66,6 +66,33 @@
spin_unlock_irqrestore(&queue->lock, flags);
}
+static void msm_drain_eventq(struct msm_device_queue *queue)
+{
+ unsigned long flags;
+ struct msm_queue_cmd *qcmd;
+ spin_lock_irqsave(&queue->lock, flags);
+ while (!list_empty(&queue->list)) {
+ qcmd = list_first_entry(&queue->list,
+ struct msm_queue_cmd, list_eventdata);
+ list_del_init(&qcmd->list_eventdata);
+ kfree(qcmd->command);
+ free_qcmd(qcmd);
+ }
+ spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static int32_t msm_find_free_queue(void)
+{
+ int i;
+ for (i = 0; i < NUM_SERVER_QUEUE; i++) {
+ struct msm_cam_server_queue *queue;
+ queue = &g_server_dev.server_queue[i];
+ if (!queue->queue_active)
+ return i;
+ }
+ return -EINVAL;
+}
+
/* callback function from all subdevices of a msm_cam_v4l2_device */
static void msm_cam_v4l2_subdev_notify(struct v4l2_subdev *sd,
unsigned int notification, void *arg)
@@ -86,29 +113,46 @@
}
}
-static int msm_ctrl_cmd_done(void __user *arg)
+static int msm_ctrl_cmd_done(void *arg)
{
void __user *uptr;
struct msm_queue_cmd *qcmd;
- struct msm_ctrl_cmd *command = &g_server_dev.ctrl;
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ struct msm_ctrl_cmd *command =
+ kzalloc(sizeof(struct msm_ctrl_cmd), GFP_KERNEL);
+ if (!command) {
+ pr_err("%s Insufficient memory. return", __func__);
+ return -ENOMEM;
+ }
D("%s\n", __func__);
-
- if (copy_from_user(command, arg,
- sizeof(struct msm_ctrl_cmd)))
+ if (copy_from_user(command, (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_ctrl_cmd))) {
+ pr_err("%s: copy_from_user failed, size=%d\n",
+ __func__, sizeof(struct msm_ctrl_cmd));
return -EINVAL;
+ }
+ g_server_dev.server_queue[command->queue_idx].ctrl = command;
+ if (command->evt_id !=
+ g_server_dev.server_queue[command->queue_idx].evt_id) {
+ pr_err("Invalid event id from userspace\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&g_server_dev.server_queue_lock);
qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
atomic_set(&qcmd->on_heap, 1);
uptr = command->value;
qcmd->command = command;
if (command->length > 0) {
- command->value = g_server_dev.ctrl_data;
- if (command->length > sizeof(g_server_dev.ctrl_data)) {
+ command->value =
+ g_server_dev.server_queue[command->queue_idx].ctrl_data;
+ if (command->length > max_control_command_size) {
pr_err("%s: user data %d is too big (max %d)\n",
__func__, command->length,
- sizeof(g_server_dev.ctrl_data));
+ max_control_command_size);
free_qcmd(qcmd);
return -EINVAL;
}
@@ -117,8 +161,9 @@
return -EINVAL;
}
}
-
- msm_enqueue(&g_server_dev.ctrl_q, &qcmd->list_control);
+ msm_enqueue(&g_server_dev.server_queue
+ [command->queue_idx].ctrl_q, &qcmd->list_control);
+ mutex_unlock(&g_server_dev.server_queue_lock);
return 0;
}
@@ -129,8 +174,10 @@
int rc = 0;
void *value;
struct msm_queue_cmd *rcmd;
+ struct msm_queue_cmd *event_qcmd;
struct msm_ctrl_cmd *ctrlcmd;
- struct msm_device_queue *queue = &server_dev->ctrl_q;
+ struct msm_device_queue *queue =
+ &server_dev->server_queue[out->queue_idx].ctrl_q;
struct v4l2_event v4l2_evt;
struct msm_isp_event_ctrl *isp_event;
@@ -139,19 +186,38 @@
pr_err("%s Insufficient memory. return", __func__);
return -ENOMEM;
}
- D("%s\n", __func__);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!event_qcmd) {
+ pr_err("%s Insufficient memory. return", __func__);
+ return -ENOMEM;
+ }
+ D("%s\n", __func__);
+ mutex_lock(&server_dev->server_queue_lock);
+ if (++server_dev->server_evt_id == 0)
+ server_dev->server_evt_id++;
+
+ server_dev->server_queue[out->queue_idx].evt_id =
+ server_dev->server_evt_id;
v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2;
+ v4l2_evt.u.data[0] = out->queue_idx;
/* setup event object to transfer the command; */
- *((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event;
isp_event->resptype = MSM_CAM_RESP_V4L2;
isp_event->isp_data.ctrl = *out;
+ isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = isp_event;
+
+ msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
+ &event_qcmd->list_eventdata);
+
/* now send command to config thread in userspace,
* and wait for results */
v4l2_event_queue(server_dev->server_command_queue.pvdev,
&v4l2_evt);
-
D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+ mutex_unlock(&server_dev->server_queue_lock);
/* wait for config return status */
D("Waiting for config status\n");
@@ -163,9 +229,6 @@
if (!rc)
rc = -ETIMEDOUT;
if (rc < 0) {
- rcmd = msm_dequeue(queue, list_control);
- if (!rcmd)
- free_qcmd(rcmd);
kfree(isp_event);
pr_err("%s: wait_event error %d\n", __func__, rc);
return rc;
@@ -184,6 +247,9 @@
memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
out->value = value;
+ kfree(ctrlcmd);
+ server_dev->server_queue[out->queue_idx].ctrl = NULL;
+
free_qcmd(rcmd);
kfree(isp_event);
D("%s: rc %d\n", __func__, rc);
@@ -201,7 +267,7 @@
}
/*send open command to server*/
-static int msm_send_open_server(int vnode_id)
+static int msm_send_open_server(struct msm_cam_v4l2_device *pcam)
{
int rc = 0;
struct msm_ctrl_cmd ctrlcmd;
@@ -211,7 +277,8 @@
ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
MAX_DEV_NAME_LEN)+1;
ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[0];
- ctrlcmd.vnode_id = vnode_id;
+ ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
@@ -220,7 +287,7 @@
return rc;
}
-static int msm_send_close_server(int vnode_id)
+static int msm_send_close_server(struct msm_cam_v4l2_device *pcam)
{
int rc = 0;
struct msm_ctrl_cmd ctrlcmd;
@@ -230,7 +297,8 @@
ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
MAX_DEV_NAME_LEN)+1;
ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[0];
- ctrlcmd.vnode_id = vnode_id;
+ ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
@@ -275,6 +343,7 @@
ctrlcmd.value = (void *)&plane_info;
ctrlcmd.timeout_ms = 10000;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
@@ -339,6 +408,7 @@
ctrlcmd.value = (void *)&plane_info;
ctrlcmd.timeout_ms = 10000;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
/* send command to config thread in usersspace, and get return value */
rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -367,6 +437,7 @@
ctrlcmd.value = NULL;
ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
@@ -388,6 +459,7 @@
ctrlcmd.value = NULL;
ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
@@ -446,6 +518,7 @@
ctrlcmd.value = (void *)ctrl_data;
ctrlcmd.timeout_ms = 1000;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -499,6 +572,7 @@
memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
ctrlcmd.timeout_ms = 1000;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
@@ -530,6 +604,7 @@
memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
ctrlcmd.timeout_ms = 1000;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
@@ -556,6 +631,7 @@
memcpy(ctrlcmd.value, queryctrl, ctrlcmd.length);
ctrlcmd.timeout_ms = 1000;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in userspace, and get return value */
@@ -666,6 +742,7 @@
ctrlcmd.value = (void *)crop;
ctrlcmd.timeout_ms = 1000;
ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
@@ -1429,6 +1506,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
int ion_client_created = 0;
#endif
+ int server_q_idx = 0;
/*struct msm_isp_ops *p_isp = 0;*/
/* get the video device */
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
@@ -1449,6 +1527,11 @@
if (pcam->dev_inst[i] == NULL)
break;
}
+
+ server_q_idx = msm_find_free_queue();
+ if (server_q_idx < 0)
+ return server_q_idx;
+
/* if no instance is available, return error */
if (i == MSM_DEV_INST_MAX) {
mutex_unlock(&pcam->vid_lock);
@@ -1469,6 +1552,15 @@
pcam->vnode_id, pcam->use_count);
pcam->use_count++;
if (pcam->use_count == 1) {
+ struct msm_cam_server_queue *queue;
+ pcam->server_queue_idx = server_q_idx;
+ queue = &g_server_dev.server_queue[server_q_idx];
+ queue->ctrl = NULL;
+ queue->ctrl_data = kzalloc(sizeof(uint8_t) *
+ max_control_command_size, GFP_KERNEL);
+ msm_queue_init(&queue->ctrl_q, "control");
+ msm_queue_init(&queue->eventData_q, "eventdata");
+ queue->queue_active = 1;
rc = msm_cam_server_open_session(&g_server_dev, pcam);
if (rc < 0) {
@@ -1530,8 +1622,7 @@
if (pcam->use_count == 1) {
- msm_queue_init(&g_server_dev.ctrl_q, "control");
- rc = msm_send_open_server(pcam->vnode_id);
+ rc = msm_send_open_server(pcam);
if (rc < 0) {
mutex_unlock(&pcam->vid_lock);
pr_err("%s failed\n", __func__);
@@ -1630,6 +1721,7 @@
int rc = 0;
struct msm_cam_v4l2_device *pcam;
struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_cam_server_queue *queue;
pcam_inst = container_of(f->private_data,
struct msm_cam_v4l2_dev_inst, eventHandle);
pcam = pcam_inst->pcam;
@@ -1637,10 +1729,6 @@
pr_err("%s NULL pointer of camera device!\n", __func__);
return -EINVAL;
}
- if (!g_server_dev.use_count) {
- pr_err("%s: error, daemon not yet started.", __func__);
- return -EINVAL;
- }
mutex_lock(&pcam->vid_lock);
@@ -1679,7 +1767,7 @@
pr_err("msm_cam_server_close_session fails %d\n", rc);
if (g_server_dev.use_count > 0) {
- rc = msm_send_close_server(pcam->vnode_id);
+ rc = msm_send_close_server(pcam);
if (rc < 0)
pr_err("msm_send_close_server failed %d\n", rc);
}
@@ -1691,6 +1779,14 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
kref_put(&pcam->mctl.refcount, msm_release_ion_client);
#endif
+ queue = &g_server_dev.server_queue[pcam->server_queue_idx];
+ queue->queue_active = 0;
+ kfree(queue->ctrl);
+ queue->ctrl = NULL;
+ kfree(queue->ctrl_data);
+ queue->ctrl_data = NULL;
+ msm_queue_drain(&queue->ctrl_q, list_control);
+ msm_drain_eventq(&queue->eventData_q);
if (g_server_dev.use_count == 0)
mutex_unlock(&g_server_dev.server_lock);
}
@@ -1741,23 +1837,23 @@
return rc;
}
-static long msm_ioctl_server(struct file *fp, unsigned int cmd,
- unsigned long arg)
+static long msm_ioctl_server(struct file *file, void *fh,
+ bool valid_prio, int cmd, void *arg)
{
int rc = -EINVAL;
- struct v4l2_event ev;
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
struct msm_camera_info temp_cam_info;
struct msm_cam_config_dev_info temp_config_info;
struct msm_mctl_node_info temp_mctl_info;
- struct v4l2_event_subscription temp_sub;
int i;
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
- case MSM_CAM_IOCTL_GET_CAMERA_INFO:
- if (copy_from_user(&temp_cam_info, (void __user *)arg,
- sizeof(struct msm_camera_info))) {
+ case MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO:
+ if (copy_from_user(&temp_cam_info,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_camera_info))) {
rc = -EINVAL;
return rc;
}
@@ -1781,18 +1877,20 @@
}
temp_cam_info.num_cameras =
g_server_dev.camera_info.num_cameras;
- if (copy_to_user((void __user *)arg,
- &temp_cam_info,
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ &temp_cam_info,
sizeof(struct msm_camera_info))) {
- rc = -EINVAL;
- return rc;
+ rc = -EINVAL;
+ return rc;
}
rc = 0;
break;
- case MSM_CAM_IOCTL_GET_CONFIG_INFO:
- if (copy_from_user(&temp_config_info, (void __user *)arg,
- sizeof(struct msm_cam_config_dev_info))) {
+ case MSM_CAM_V4L2_IOCTL_GET_CONFIG_INFO:
+ if (copy_from_user(&temp_config_info,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_cam_config_dev_info))) {
+
rc = -EINVAL;
return rc;
}
@@ -1808,7 +1906,7 @@
}
temp_config_info.num_config_nodes =
g_server_dev.config_info.num_config_nodes;
- if (copy_to_user((void __user *)arg,
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
&temp_config_info,
sizeof(struct msm_cam_config_dev_info))) {
rc = -EINVAL;
@@ -1816,13 +1914,13 @@
}
rc = 0;
break;
- case MSM_CAM_IOCTL_GET_MCTL_INFO:
- if (copy_from_user(&temp_mctl_info, (void __user *)arg,
- sizeof(struct msm_mctl_node_info))) {
+ case MSM_CAM_V4L2_IOCTL_GET_MCTL_INFO:
+ if (copy_from_user(&temp_mctl_info,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_mctl_node_info))) {
rc = -EINVAL;
return rc;
}
-
for (i = 0; i < g_server_dev.mctl_node_info.num_mctl_nodes;
i++) {
if (copy_to_user((void __user *)
@@ -1836,7 +1934,7 @@
}
temp_mctl_info.num_mctl_nodes =
g_server_dev.mctl_node_info.num_mctl_nodes;
- if (copy_to_user((void __user *)arg,
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
&temp_mctl_info,
sizeof(struct msm_mctl_node_info))) {
rc = -EINVAL;
@@ -1845,122 +1943,79 @@
rc = 0;
break;
- case VIDIOC_SUBSCRIBE_EVENT:
- if (copy_from_user(&temp_sub, (void __user *)arg,
- sizeof(struct v4l2_event_subscription))) {
+ case MSM_CAM_V4L2_IOCTL_CTRL_CMD_DONE:
+ D("%s: MSM_CAM_IOCTL_CTRL_CMD_DONE\n", __func__);
+ rc = msm_ctrl_cmd_done(arg);
+ break;
+
+ case MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD: {
+ struct msm_queue_cmd *event_cmd;
+ struct msm_isp_event_ctrl u_isp_event;
+ struct msm_isp_event_ctrl *k_isp_event;
+ struct msm_device_queue *queue;
+ void __user *u_ctrl_value = NULL;
+ if (copy_from_user(&u_isp_event,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_isp_event_ctrl))) {
rc = -EINVAL;
return rc;
}
- rc = msm_server_v4l2_subscribe_event
- (&g_server_dev.server_command_queue.eventHandle,
- &temp_sub);
- if (rc < 0)
+ queue = &g_server_dev.server_queue
+ [u_isp_event.isp_data.ctrl.queue_idx].eventData_q;
+ event_cmd = msm_dequeue(queue, list_eventdata);
+ if (!event_cmd) {
+ pr_err("%s: No event payload\n", __func__);
+ rc = -EINVAL;
return rc;
-
- break;
-
- case VIDIOC_DQEVENT: {
- void __user *u_ctrl_value = NULL, *user_ptr = NULL;
- struct msm_isp_event_ctrl u_isp_event;
- struct msm_isp_event_ctrl *k_isp_event;
-
- /* First, copy the event structure from userspace */
- D("%s: VIDIOC_DQEVENT\n", __func__);
- if (copy_from_user(&ev, (void __user *)arg,
- sizeof(struct v4l2_event))) {
- break;
}
- /* Next, get the pointer to event_ctrl structure
- * embedded inside the v4l2_event.u.data array. */
- user_ptr = (void __user *)(*((uint32_t *)ev.u.data));
-
- /* Next, copy the userspace event ctrl structure */
- if (copy_from_user((void *)&u_isp_event, user_ptr,
- sizeof(struct msm_isp_event_ctrl))) {
- break;
- }
+ k_isp_event = (struct msm_isp_event_ctrl *)
+ event_cmd->command;
+ free_qcmd(event_cmd);
/* Save the pointer of the user allocated command buffer*/
u_ctrl_value = u_isp_event.isp_data.ctrl.value;
- /* Dequeue the event queued into the v4l2 queue*/
- rc = v4l2_event_dequeue(
- &g_server_dev.server_command_queue.eventHandle,
- &ev, fp->f_flags & O_NONBLOCK);
- if (rc < 0) {
- pr_err("no pending events?");
- break;
- }
-
- /* Use k_isp_event to point to the event_ctrl structure
- * embedded inside v4l2_event.u.data */
- k_isp_event = (struct msm_isp_event_ctrl *)
- (*((uint32_t *)ev.u.data));
- if (!k_isp_event) {
- pr_err("%s Invalid event ctrl structure. ", __func__);
- break;
- }
-
/* Copy the event structure into user struct*/
u_isp_event = *k_isp_event;
/* Restore the saved pointer of the user
* allocated command buffer. */
u_isp_event.isp_data.ctrl.value = u_ctrl_value;
- if (ev.type == V4L2_EVENT_PRIVATE_START+MSM_CAM_RESP_V4L2) {
- /* Copy the ctrl cmd, if present*/
- if (k_isp_event->isp_data.ctrl.length > 0) {
- void *k_ctrl_value =
- k_isp_event->isp_data.ctrl.value;
- if (copy_to_user(u_ctrl_value, k_ctrl_value,
- k_isp_event->isp_data.ctrl.length)) {
- rc = -EINVAL;
- break;
- }
- }
- /* Copy the event ctrl structure back into
- * user's structure. */
- if (copy_to_user(user_ptr, (void *)&u_isp_event,
- sizeof(struct msm_isp_event_ctrl))) {
+
+ /* Copy the ctrl cmd, if present*/
+ if (k_isp_event->isp_data.ctrl.length > 0) {
+ void *k_ctrl_value =
+ k_isp_event->isp_data.ctrl.value;
+ if (copy_to_user(u_ctrl_value, k_ctrl_value,
+ k_isp_event->isp_data.ctrl.length)) {
rc = -EINVAL;
break;
}
}
-
- /* Copy the v4l2_event structure back to the user*/
- if (copy_to_user((void __user *)arg, &ev,
- sizeof(struct v4l2_event))) {
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ &u_isp_event,
+ sizeof(struct msm_isp_event_ctrl))) {
rc = -EINVAL;
- break;
+ return rc;
}
- }
+ rc = 0;
break;
-
- case MSM_CAM_IOCTL_CTRL_CMD_DONE:
- D("%s: MSM_CAM_IOCTL_CTRL_CMD_DONE\n", __func__);
- rc = msm_ctrl_cmd_done((void __user *)arg);
- break;
-
+ }
default:
break;
}
return rc;
}
-static int msm_open_server(struct inode *inode, struct file *fp)
+static int msm_open_server(struct file *fp)
{
- int rc;
+ int rc = 0;
D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
mutex_lock(&g_server_dev.server_lock);
- rc = nonseekable_open(inode, fp);
- if (rc < 0) {
- pr_err("%s: nonseekable_open error %d\n", __func__, rc);
- mutex_unlock(&g_server_dev.server_lock);
- return rc;
- }
g_server_dev.use_count++;
if (g_server_dev.use_count == 1)
- msm_queue_init(&g_server_dev.ctrl_q, "control");
+ fp->private_data =
+ &g_server_dev.server_command_queue.eventHandle;
mutex_unlock(&g_server_dev.server_lock);
return rc;
}
@@ -1982,8 +2037,9 @@
return rc;
}
-static int msm_close_server(struct inode *inode, struct file *fp)
+static int msm_close_server(struct file *fp)
{
+ D("%s\n", __func__);
mutex_lock(&g_server_dev.server_lock);
if (g_server_dev.use_count > 0)
g_server_dev.use_count--;
@@ -1999,7 +2055,6 @@
v4l2_event_queue(
g_server_dev.pcam_active->pvdev, &v4l2_ev);
}
- msm_queue_drain(&g_server_dev.ctrl_q, list_control);
}
return 0;
}
@@ -2269,14 +2324,19 @@
* which will create a config device (/dev/config0/ and plug in
* ISP's operation "v4l2_ioctl_ops*"
*/
-static const struct file_operations msm_fops_server = {
+static const struct v4l2_file_operations msm_fops_server = {
.owner = THIS_MODULE,
.open = msm_open_server,
.poll = msm_poll_server,
- .unlocked_ioctl = msm_ioctl_server,
+ .unlocked_ioctl = video_ioctl2,
.release = msm_close_server,
};
+static const struct v4l2_ioctl_ops msm_ioctl_ops_server = {
+ .vidioc_subscribe_event = msm_server_v4l2_subscribe_event,
+ .vidioc_default = msm_ioctl_server,
+};
+
static const struct file_operations msm_fops_config = {
.owner = THIS_MODULE,
.open = msm_open_config,
@@ -2379,53 +2439,70 @@
}
-static int msm_setup_server_dev(int node, char *device_name)
+static int msm_setup_server_dev(struct platform_device *pdev)
{
- int rc = -ENODEV;
- struct device *device_server;
- int dev_num = node;
- dev_t devno;
+ int rc = -ENODEV, i;
D("%s\n", __func__);
+ g_server_dev.server_pdev = pdev;
+ g_server_dev.v4l2_dev.dev = &pdev->dev;
- devno = MKDEV(MAJOR(msm_devno), dev_num);
- device_server = device_create(msm_class, NULL,
- devno, NULL, "%s", device_name);
+ rc = v4l2_device_register(g_server_dev.v4l2_dev.dev,
+ &g_server_dev.v4l2_dev);
+ if (rc < 0)
+ return -EINVAL;
- if (IS_ERR(device_server)) {
- rc = PTR_ERR(device_server);
- pr_err("%s: error creating device: %d\n", __func__, rc);
+ g_server_dev.video_dev = video_device_alloc();
+ if (g_server_dev.video_dev == NULL) {
+ pr_err("%s: video_device_alloc failed\n", __func__);
return rc;
}
- cdev_init(&g_server_dev.server_cdev, &msm_fops_server);
- g_server_dev.server_cdev.owner = THIS_MODULE;
+ strlcpy(g_server_dev.video_dev->name, pdev->name,
+ sizeof(g_server_dev.video_dev->name));
- rc = cdev_add(&g_server_dev.server_cdev, devno, 1);
- if (rc < 0) {
- pr_err("%s: error adding cdev: %d\n", __func__, rc);
- device_destroy(msm_class, devno);
- return rc;
- }
+ g_server_dev.video_dev->v4l2_dev = &g_server_dev.v4l2_dev;
+ g_server_dev.video_dev->fops = &msm_fops_server;
+ g_server_dev.video_dev->ioctl_ops = &msm_ioctl_ops_server;
+ g_server_dev.video_dev->release = video_device_release;
+ g_server_dev.video_dev->minor = 100;
+ g_server_dev.video_dev->vfl_type = 1;
+
+ video_set_drvdata(g_server_dev.video_dev, &g_server_dev);
+
+ strlcpy(g_server_dev.media_dev.model, "qcamera",
+ sizeof(g_server_dev.media_dev.model));
+ g_server_dev.media_dev.dev = &pdev->dev;
+ rc = media_device_register(&g_server_dev.media_dev);
+ g_server_dev.v4l2_dev.mdev = &g_server_dev.media_dev;
+
+ rc = video_register_device(g_server_dev.video_dev,
+ VFL_TYPE_GRABBER, 100);
mutex_init(&g_server_dev.server_lock);
+ mutex_init(&g_server_dev.server_queue_lock);
g_server_dev.pcam_active = NULL;
g_server_dev.camera_info.num_cameras = 0;
atomic_set(&g_server_dev.number_pcam_active, 0);
+ g_server_dev.server_evt_id = 0;
/*initialize fake video device and event queue*/
- g_server_dev.server_command_queue.pvdev = video_device_alloc();
- if (g_server_dev.server_command_queue.pvdev == NULL) {
- pr_err("%s: video_device_alloc failed\n", __func__);
- return -ENOMEM;
- }
+ g_server_dev.server_command_queue.pvdev = g_server_dev.video_dev;
rc = msm_setup_v4l2_event_queue(
&g_server_dev.server_command_queue.eventHandle,
g_server_dev.server_command_queue.pvdev);
+
if (rc < 0)
pr_err("%s failed to initialize event queue\n", __func__);
+ for (i = 0; i < NUM_SERVER_QUEUE; i++) {
+ struct msm_cam_server_queue *queue;
+ queue = &g_server_dev.server_queue[i];
+ queue->queue_active = 0;
+ msm_queue_init(&queue->ctrl_q, "control");
+ msm_queue_init(&queue->eventData_q, "eventdata");
+ }
return rc;
}
@@ -2717,7 +2794,7 @@
}
EXPORT_SYMBOL(msm_sensor_register);
-static int __init msm_camera_init(void)
+static int __devinit msm_camera_probe(struct platform_device *pdev)
{
int rc = 0, i;
/*for now just create a config 0 node
@@ -2749,7 +2826,7 @@
}
D("creating server and config nodes\n");
- rc = msm_setup_server_dev(0, "video_msm");
+ rc = msm_setup_server_dev(pdev);
if (rc < 0) {
pr_err("%s: failed to create server dev: %d\n", __func__,
rc);
@@ -2769,10 +2846,31 @@
return rc;
}
-static void __exit msm_camera_exit(void)
+static int __exit msm_camera_exit(struct platform_device *pdev)
{
msm_isp_unregister(&g_server_dev);
+ return 0;
+}
+
+
+static struct platform_driver msm_cam_server_driver = {
+ .probe = msm_camera_probe,
+ .remove = msm_camera_exit,
+ .driver = {
+ .name = "msm_cam_server",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_camera_init(void)
+{
+ return platform_driver_register(&msm_cam_server_driver);
+}
+
+static void __exit msm_cam_server_exit(void)
+{
+ platform_driver_unregister(&msm_cam_server_driver);
}
module_init(msm_camera_init);
-module_exit(msm_camera_exit);
+module_exit(msm_cam_server_exit);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index dd65c01..c4373a7 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -356,6 +356,7 @@
* control thread. It is accessed only from a process context.
* TO BE REMOVED
*/
+ uint32_t server_queue_idx;
struct msm_device_queue ctrl_q;
struct mutex lock;
@@ -387,11 +388,27 @@
struct msm_mem_map_info mem_map;
};
+#define NUM_SERVER_QUEUE 5
+
+struct msm_cam_server_queue {
+ uint32_t queue_active;
+ struct msm_device_queue ctrl_q;
+ struct msm_device_queue eventData_q;
+ struct msm_ctrl_cmd *ctrl;
+ uint8_t *ctrl_data;
+ uint32_t evt_id;
+};
+
/* abstract camera server device for all sensor successfully probed*/
struct msm_cam_server_dev {
/* config node device*/
- struct cdev server_cdev;
+ struct platform_device *server_pdev;
+ /* server node v4l2 device */
+ struct v4l2_device v4l2_dev;
+ struct video_device *video_dev;
+ struct media_device media_dev;
+
/* info of sensors successfully probed*/
struct msm_camera_info camera_info;
/* info of configs successfully created*/
@@ -401,18 +418,20 @@
/* number of camera devices opened*/
atomic_t number_pcam_active;
struct v4l2_queue_util server_command_queue;
+
/* This queue used by the config thread to send responses back to the
* control thread. It is accessed only from a process context.
*/
- struct msm_device_queue ctrl_q;
- uint8_t ctrl_data[max_control_command_size];
- struct msm_ctrl_cmd ctrl;
+ struct msm_cam_server_queue server_queue[NUM_SERVER_QUEUE];
+ uint32_t server_evt_id;
+
int use_count;
/* all the registered ISP subdevice*/
struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
/* info of MCTL nodes successfully probed*/
struct msm_mctl_node_info mctl_node_info;
struct mutex server_lock;
+ struct mutex server_queue_lock;
};
/* camera server related functions */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 980599c..7aae5e1 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -148,50 +148,44 @@
#define MSM_CAM_IOCTL_PUT_ST_FRAME \
_IOW(MSM_CAM_IOCTL_MAGIC, 39, struct msm_camera_st_frame *)
-#define MSM_CAM_IOCTL_GET_CONFIG_INFO \
- _IOR(MSM_CAM_IOCTL_MAGIC, 40, struct msm_cam_config_dev_info *)
-
#define MSM_CAM_IOCTL_V4L2_EVT_NOTIFY \
- _IOR(MSM_CAM_IOCTL_MAGIC, 41, struct v4l2_event *)
+ _IOR(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event *)
#define MSM_CAM_IOCTL_SET_MEM_MAP_INFO \
- _IOR(MSM_CAM_IOCTL_MAGIC, 42, struct msm_mem_map_info *)
+ _IOR(MSM_CAM_IOCTL_MAGIC, 41, struct msm_mem_map_info *)
#define MSM_CAM_IOCTL_ACTUATOR_IO_CFG \
- _IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_actuator_cfg_data *)
+ _IOW(MSM_CAM_IOCTL_MAGIC, 42, struct msm_actuator_cfg_data *)
#define MSM_CAM_IOCTL_MCTL_POST_PROC \
- _IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_mctl_post_proc_cmd *)
+ _IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_mctl_post_proc_cmd *)
#define MSM_CAM_IOCTL_RESERVE_FREE_FRAME \
- _IOW(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *)
+ _IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_cam_evt_divert_frame *)
#define MSM_CAM_IOCTL_RELEASE_FREE_FRAME \
- _IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_cam_evt_divert_frame *)
+ _IOR(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *)
#define MSM_CAM_IOCTL_PICT_PP_DIVERT_DONE \
- _IOR(MSM_CAM_IOCTL_MAGIC, 47, struct msm_pp_frame *)
+ _IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_pp_frame *)
#define MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL \
- _IOR(MSM_CAM_IOCTL_MAGIC, 48, struct v4l2_control)
+ _IOR(MSM_CAM_IOCTL_MAGIC, 47, struct v4l2_control)
#define MSM_CAM_IOCTL_SENSOR_V4l2_QUERY_CTRL \
- _IOR(MSM_CAM_IOCTL_MAGIC, 49, struct v4l2_queryctrl)
+ _IOR(MSM_CAM_IOCTL_MAGIC, 48, struct v4l2_queryctrl)
#define MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME \
- _IOW(MSM_CAM_IOCTL_MAGIC, 50, struct timeval *)
+ _IOW(MSM_CAM_IOCTL_MAGIC, 49, struct timeval *)
#define MSM_CAM_IOCTL_SET_VFE_OUTPUT_TYPE \
- _IOW(MSM_CAM_IOCTL_MAGIC, 51, uint32_t *)
-
-#define MSM_CAM_IOCTL_GET_MCTL_INFO \
- _IOR(MSM_CAM_IOCTL_MAGIC, 52, struct msm_mctl_node_info *)
+ _IOW(MSM_CAM_IOCTL_MAGIC, 50, uint32_t *)
#define MSM_CAM_IOCTL_MCTL_DIVERT_DONE \
- _IOR(MSM_CAM_IOCTL_MAGIC, 53, struct msm_cam_evt_divert_frame *)
+ _IOR(MSM_CAM_IOCTL_MAGIC, 51, struct msm_cam_evt_divert_frame *)
#define MSM_CAM_IOCTL_GET_ACTUATOR_INFO \
- _IOW(MSM_CAM_IOCTL_MAGIC, 54, struct msm_actuator_cfg_data *)
+ _IOW(MSM_CAM_IOCTL_MAGIC, 52, struct msm_actuator_cfg_data *)
struct msm_mctl_pp_cmd {
int32_t id;
@@ -260,6 +254,8 @@
uint32_t timeout_ms;
int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */
int vnode_id; /* video dev id. Can we overload resp_fd? */
+ int queue_idx;
+ uint32_t evt_id;
uint32_t stream_type; /* used to pass value to qcamera server */
int config_ident; /*used as identifier for config node*/
};
@@ -1363,4 +1359,23 @@
#define QCAMERA_DEVICE_GROUP_ID 1
#define QCAMERA_VNODE_GROUP_ID 2
+#define MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t *)
+
+#define MSM_CAM_V4L2_IOCTL_GET_CONFIG_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t *)
+
+#define MSM_CAM_V4L2_IOCTL_GET_MCTL_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t *)
+
+#define MSM_CAM_V4L2_IOCTL_CTRL_CMD_DONE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t *)
+
+#define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t *)
+
+struct msm_camera_v4l2_ioctl_t {
+ void __user *ioctl_ptr;
+};
+
#endif /* __LINUX_MSM_CAMERA_H */