static int overlay_mem = 640*480*2;
+/*
+ * Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable need not to be balanced.
+ */
+static int camera_sensor_if_enable(struct camera_device *cam)
+{
+ int rval;
+ struct v4l2_ifparm p;
+
+ rval = vidioc_int_g_ifparm(cam->sdev, &p);
+ if (rval) {
+ dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+ return rval;
+ }
+
+ cam->if_type = p.if_type;
+
+ switch (p.if_type) {
+ case V4L2_IF_TYPE_BT656:
+ cam->if_u.bt656.xclk =
+ cam->cam_hardware->set_xclk(cam->if_u.bt656.xclk,
+ cam->hardware_data);
+ break;
+ default:
+ /* FIXME: how about other interfaces? */
+ dev_err(cam->dev, "interface type %d not supported\n",
+ p.if_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void camera_sensor_if_disable(const struct camera_device *cam)
+{
+ switch (cam->if_type) {
+ case V4L2_IF_TYPE_BT656:
+ break;
+ }
+}
+
+/*
+ * Initialise the sensor hardware.
+ */
+static int camera_sensor_init(struct camera_device *cam)
+{
+ int err = 0;
+ struct v4l2_int_device *sdev = cam->sdev;
+
+ /* Enable the xclk output. The sensor may (and does, in the case of
+ * the OV9640) require an xclk input in order for its initialization
+ * routine to work.
+ */
+
+ cam->if_u.bt656.xclk = 21000000;/* choose an arbitrary xclk frequency */
+
+ cam->if_u.bt656.xclk = cam->cam_hardware->set_xclk(cam->if_u.bt656.xclk,
+ cam->hardware_data);
+
+ err = camera_sensor_if_enable(cam);
+ if (err) {
+ dev_err(cam->dev, "sensor interface could not be enabled at "
+ "initialisation, %d\n", err);
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ /* power up sensor during sensor initialization */
+ vidioc_int_s_power(sdev, 1);
+
+ err = vidioc_int_dev_init(sdev);
+ if (err) {
+ dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+ /* Sensor init failed --- it's nonexistent to us! */
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+ camera_sensor_if_disable(cam);
+
+ vidioc_int_s_power(sdev, 0);
+
+ return err;
+}
+
+static void camera_sensor_exit(struct camera_device *cam)
+{
+ if (cam->sdev)
+ vidioc_int_dev_exit(cam->sdev);
+}
+
/* DMA completion routine for the scatter-gather DMA fragments. */
/* This function is called when a scatter DMA fragment is completed */
static void
sgdma = cam->sgdma + sgslot;
if (!sgdma->queued_sglist) {
spin_unlock(&cam->sg_lock);
- dev_err(&cam->dev, "SGDMA completed when none queued\n");
+ dev_err(cam->dev, "SGDMA completed when none queued\n");
return;
}
if (!--sgdma->queued_sglist) {
static int
camera_core_vbq_setup(struct videobuf_queue *q, unsigned int *cnt, unsigned int *size)
{
- struct camera_device *cam = q->priv_data;
+ struct camera_fh *fh = q->priv_data;
+ struct camera_device *cam = fh->cam;
if (*cnt <= 0)
*cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
camera_core_vbq_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
- struct camera_device *cam = q->priv_data;
+ struct camera_fh *fh = q->priv_data;
+ struct camera_device *cam = fh->cam;
int err = 0;
spin_lock(&cam->img_lock);
static void
camera_core_vbq_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
- struct camera_device *cam = q->priv_data;
+ struct camera_fh *fh = q->priv_data;
+ struct camera_device *cam = fh->cam;
enum videobuf_state state = vb->state;
int err;
* scatter-gather DMA slots as video buffers so that can't
* happen.
*/
- dev_dbg(&cam->dev, "Failed to queue a video buffer for SGDMA\n");
+ dev_dbg(cam->dev, "Failed to queue a video buffer for SGDMA\n");
vb->state = state;
}
}
struct camera_fh *ofh = fh;
struct camera_device *cam = ofh->cam;
- return cam->cam_sensor->enum_pixformat(f, cam->sensor_data);
+ return vidioc_int_enum_fmt_cap(cam->sdev, f);
}
static int vidioc_g_fmt_cap(struct file *file, void *fh,
{
struct camera_fh *ofh = fh;
struct camera_device *cam = ofh->cam;
- unsigned int temp_sizeimage = 0;
+ int rval = 0;
+
+ vidioc_int_try_fmt_cap(cam->sdev, f);
- temp_sizeimage = cam->pix.sizeimage;
- cam->cam_sensor->try_format(&f->fmt.pix, cam->sensor_data);
cam->pix = f->fmt.pix;
- cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
- &cam->nominal_timeperframe, cam->sensor_data);
- cam->cparm.timeperframe = cam->nominal_timeperframe;
- cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
- return cam->cam_sensor->configure(&cam->pix, cam->xclk,
- &cam->cparm.timeperframe, cam->sensor_data);
+ rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+ camera_sensor_if_enable(cam);
+
+ return rval;
}
static int vidioc_try_fmt_cap(struct file *file, void *fh,
struct camera_fh *ofh = fh;
struct camera_device *cam = ofh->cam;
- return cam->cam_sensor->try_format(&f->fmt.pix, cam->sensor_data);
+ return vidioc_int_try_fmt_cap(cam->sdev, f);
}
static int vidioc_reqbufs(struct file *file, void *fh,
struct camera_fh *ofh = fh;
struct camera_device *cam = ofh->cam;
- return cam->cam_sensor->query_control(a, cam->sensor_data);
+ return vidioc_int_queryctrl(cam->sdev, a);
}
static int vidioc_g_ctrl(struct file *file, void *fh,
struct camera_fh *ofh = fh;
struct camera_device *cam = ofh->cam;
- return cam->cam_sensor->get_control(a, cam->sensor_data);
+ return vidioc_int_g_ctrl(cam->sdev, a);
}
static int vidioc_s_ctrl(struct file *file, void *fh,
struct camera_fh *ofh = fh;
struct camera_device *cam = ofh->cam;
- return cam->cam_sensor->set_control(a, cam->sensor_data);
+ return vidioc_int_s_ctrl(cam->sdev, a);
}
static int vidioc_g_fbuf(struct file *file, void *fh,
GFP_KERNEL | GFP_DMA);
}
if (!cam->capture_base) {
- dev_err(&cam->dev, "cannot allocate capture buffer\n");
+ dev_err(cam->dev, "cannot allocate capture buffer\n");
return 0;
}
timeout = interruptible_sleep_on_timeout
(&cam->new_video_frame, timeout);
if (timeout == 0) {
- dev_err(&cam->dev, "timeout waiting video frame\n");
+ dev_err(cam->dev, "timeout waiting video frame\n");
return -EIO; /* time out */
}
}
kfree(fh->vbq.read_buf);
}
+ module_put(cam->sdev->module);
+
cam->cam_hardware->close(cam->hardware_data);
cam->active = 0;
return 0;
int minor = iminor(inode);
struct camera_device *cam = camera_dev;
struct camera_fh *fh;
+ struct v4l2_format format;
+ int rval;
if (!cam || !cam->vfd || (cam->vfd->minor != minor))
return -ENODEV;
spin_lock(&cam->img_lock);
if (cam->active == 1) {
- dev_err(&cam->dev, "Camera device Active\n");
+ dev_err(cam->dev, "Camera device Active\n");
spin_unlock(&cam->img_lock);
- return -EPERM;
+ rval = -EPERM;
+ goto err;
}
cam->active = 1;
+
+ if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+ spin_unlock(&cam->img_lock);
+ rval = -ENODEV;
+ goto err;
+ }
+
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
spin_unlock(&cam->img_lock);
videobuf_queue_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock,
cam->capture_started = 0;
if (cam->cam_hardware->open(cam->hardware_data)) {
- dev_err(&cam->dev, "Camera IF configuration failed\n");
+ dev_err(cam->dev, "Camera IF configuration failed\n");
cam->active = 0;
- return -ENODEV;
+ rval = -ENODEV;
+ goto err;
}
-
- cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
- /* program the sensor for the capture format and rate */
- if (cam->cam_sensor->configure(&cam->pix, cam->xclk,
- &cam->cparm.timeperframe, cam->sensor_data)) {
- dev_err(&cam->dev, "Camera sensor configuration failed\n");
+ rval = vidioc_s_fmt_cap(file, fh, &format);
+ if (rval) {
+ dev_err(cam->dev, "Camera sensor configuration failed (%d)\n", rval);
cam->cam_hardware->close(cam->hardware_data);
cam->active = 0;
- return -ENODEV;
+ rval = -ENODEV;
+ goto err;
}
return 0;
+
+err:
+ module_put(cam->sdev->module);
+ kfree(fh);
+ return rval;
}
#ifdef CONFIG_PM
static int camera_core_suspend(struct platform_device *pdev, pm_message_t state)
{
struct camera_device *cam = platform_get_drvdata(pdev);
- int ret = 0;
spin_lock(&cam->img_lock);
if (cam->active)
cam->cam_hardware->close(cam->hardware_data);
- cam->cam_sensor->power_off(cam->sensor_data);
+ vidioc_int_s_power(cam->sdev, 0);
spin_unlock(&cam->img_lock);
- return ret;
+ return 0;
}
static int camera_core_resume(struct platform_device *pdev)
{
struct camera_device *cam = platform_get_drvdata(pdev);
- int ret = 0;
spin_lock(&cam->img_lock);
- cam->cam_sensor->power_on(cam->sensor_data);
+ vidioc_int_s_power(cam->sdev, 1);
if (cam->active) {
+ struct v4l2_format format;
+
cam->capture_completed = 1;
cam->cam_hardware->open(cam->hardware_data);
- cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
- cam->cam_sensor->configure(&cam->pix, cam->xclk,
- &cam->cparm.timeperframe,
- cam->sensor_data);
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
+ vidioc_int_s_fmt_cap(cam->sdev, &format);
+ camera_sensor_if_enable(cam);
+
camera_core_sgdma_process(cam);
}
spin_unlock(&cam->img_lock);
- return ret;
+ return 0;
}
#endif /* CONFIG_PM */
.open = camera_core_open,
.release = camera_core_release,
};
+static ssize_t
+camera_streaming_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct camera_device *cam = dev_get_drvdata(dev);
-static int __init camera_core_probe(struct platform_device *pdev)
+ return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
+}
+
+static DEVICE_ATTR(streaming, S_IRUGO, camera_streaming_show, NULL);
+
+static void camera_device_unregister(struct v4l2_int_device *ctl)
{
- struct camera_device *cam;
+ struct camera_device *cam = ctl->priv;
+
+ camera_sensor_exit(cam);
+}
+
+static int camera_device_register(struct v4l2_int_device *ctl,
+ struct v4l2_int_device *s)
+{
+ struct camera_device *cam = ctl->priv;
struct video_device *vfd;
- int status;
+ int rval;
+ /*Initialise the pointer to the sensor interface and camera interface */
- cam = kzalloc(sizeof(struct camera_device), GFP_KERNEL);
- if (!cam) {
- dev_err(&cam->dev, "could not allocate memory\n");
- status = -ENOMEM;
- goto err0;
- }
+ /* We already have a slave. */
+ if (cam->sdev)
+ return -EBUSY;
- /* Save the pointer to camera device in a global variable */
- camera_dev = cam;
+ cam->sdev = s;
+
+ if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+ dev_err(cam->dev, "could not register sysfs entry\n");
+ rval = -EBUSY;
+ goto err;
+ }
/* initialize the video_device struct */
vfd = cam->vfd = video_device_alloc();
if (!vfd) {
- dev_err(&cam->dev, " could not allocate video device struct\n");
- status = -ENOMEM;
- goto err1;
+ dev_err(cam->dev, " could not allocate video device struct\n");
+ rval = -ENOMEM;
+ goto err;
}
vfd->release = video_device_release;
vfd->vidioc_s_fbuf = vidioc_s_fbuf;
vfd->vidioc_overlay = vidioc_overlay;
+
+ dev_info(cam->dev, "%s interface with %s sensor\n",
+ cam->cam_hardware->name, cam->sdev->name);
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ dev_err(cam->dev, "could not register Video for Linux device\n");
+ rval = -ENODEV;
+ goto err;
+ }
+
+
+ rval = camera_sensor_init(cam);
+ if (rval)
+ goto err;
+
+ /* Disable the Camera after detection */
+ cam->cam_hardware->disable(cam->hardware_data);
+
+ return 0;
+
+err:
+ camera_device_unregister(ctl);
+
+ return rval;
+}
+
+static struct v4l2_int_master camera_master = {
+ .attach = camera_device_register,
+ .detach = camera_device_unregister,
+};
+
+static struct v4l2_int_device camera = {
+ .module = THIS_MODULE,
+ .name = CAM_NAME,
+ .type = v4l2_int_type_master,
+ .u = {
+ .master = &camera_master
+ },
+};
+
+static int __init camera_core_probe(struct platform_device *pdev)
+{
+ struct camera_device *cam;
+ int status = 0;
+
+ cam = kzalloc(sizeof(struct camera_device), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ status = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, cam);
+
+ cam->dev = &pdev->dev;
+
+ /* initialize the camera interface */
+ cam->cam_hardware = &camera_hardware_if;
+ cam->hardware_data = cam->cam_hardware->init();
+ if (!cam->hardware_data) {
+ dev_err(cam->dev, "cannot initialize interface hardware\n");
+ status = -ENODEV;
+ goto err;
+ }
+
+ /* Save the pointer to camera device in a global variable */
+ camera_dev = cam;
+
/* initialize the videobuf queue ops */
cam->vbq_ops.buf_setup = camera_core_vbq_setup;
cam->vbq_ops.buf_prepare = camera_core_vbq_prepare;
(dma_addr_t *) &cam->overlay_base_phys,
GFP_KERNEL | GFP_DMA);
if (!cam->overlay_base) {
- dev_err(&cam->dev, "cannot allocate overlay framebuffer\n");
+ dev_err(cam->dev, "cannot allocate overlay framebuffer\n");
status = -ENOMEM;
- goto err2;
+ goto err;
}
}
memset((void*)cam->overlay_base, 0, cam->overlay_size);
spin_lock_init(&cam->overlay_lock);
spin_lock_init(&cam->capture_lock);
- /*Initialise the pointer to the sensor interface and camera interface */
- cam->cam_sensor = &camera_sensor_if;
- cam->cam_hardware = &camera_hardware_if;
-
- /* initialize the camera interface */
- cam->hardware_data = cam->cam_hardware->init();
- if (!cam->hardware_data) {
- dev_err(&cam->dev, "cannot initialize interface hardware\n");
- status = -ENODEV;
- goto err3;
- }
-
/* initialize the spinlock used to serialize access to the image
* parameters
*/
spin_lock_init(&cam->img_lock);
- /* initialize the streaming capture parameters */
- cam->cparm.capability = V4L2_CAP_TIMEPERFRAME;
- cam->cparm.readbuffers = 1;
-
- /* Enable the xclk output. The sensor may (and does, in the case of
- * the OV9640) require an xclk input in order for its initialization
- * routine to work.
- */
- cam->xclk = 21000000; /* choose an arbitrary xclk frequency */
- cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
-
- /* initialize the sensor and define a default capture format cam->pix */
- cam->sensor_data = cam->cam_sensor->init(&cam->pix);
- if (!cam->sensor_data) {
- cam->cam_hardware->disable(cam->hardware_data);
- dev_err(&cam->dev, "cannot initialize sensor\n");
- status = -ENODEV;
- goto err4;
- }
-
- dev_info(&cam->dev, "%s interface with %s sensor\n",
- cam->cam_hardware->name, cam->cam_sensor->name);
-
- /* select an arbitrary default capture frame rate of 15fps */
- cam->nominal_timeperframe.numerator = 1;
- cam->nominal_timeperframe.denominator = 15;
-
- /* calculate xclk based on the default capture format and default
- * frame rate
- */
- cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
- &cam->nominal_timeperframe, cam->sensor_data);
- cam->cparm.timeperframe = cam->nominal_timeperframe;
-
/* initialise the wait queue */
init_waitqueue_head(&cam->new_video_frame);
/* Initialise the DMA structures */
camera_core_sgdma_init(cam);
- /* Disable the Camera after detection */
- cam->cam_hardware->disable(cam->hardware_data);
-
platform_set_drvdata(pdev, cam);
- if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
- dev_err(&cam->dev, "could not register Video for Linux device\n");
- status = -ENODEV;
- goto err5;
- }
+ camera.priv = cam;
- dev_info(&cam->dev, "registered device video%d [v4l2]\n", vfd->minor);
+ if (v4l2_int_device_register(&camera))
+ goto err;
return 0;
- err5:
- cam->cam_sensor->cleanup(cam->sensor_data);
- err4:
- cam->cam_hardware->cleanup(cam->hardware_data);
- err3:
- dma_free_coherent(NULL, cam->overlay_size,
- (void *)cam->overlay_base,
- cam->overlay_base_phys);
+ err:
+ vidioc_int_dev_exit(cam->sdev);
cam->overlay_base = 0;
- err2:
- video_device_release(vfd);
- err1:
- kfree(cam);
- camera_dev = NULL;
- err0:
return status;
}
}
cam->overlay_base_phys = 0;
- cam->cam_sensor->cleanup(cam->sensor_data);
+ vidioc_int_dev_exit(cam->sdev);
cam->cam_hardware->cleanup(cam->hardware_data);
kfree(cam);
camera_dev = NULL;