diff options
Diffstat (limited to 'drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c')
-rw-r--r-- | drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 402 |
1 files changed, 222 insertions, 180 deletions
diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index d2262275a870..ce26741ae9d9 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -23,6 +23,7 @@ #include <media/v4l2-event.h> #include <media/v4l2-common.h> #include <linux/delay.h> +#include <linux/platform_device.h> #include "mmal-common.h" #include "mmal-encodings.h" @@ -78,131 +79,132 @@ static const struct v4l2_fract /* video formats */ static struct mmal_fmt formats[] = { { - .name = "4:2:0, planar, YUV", - .fourcc = V4L2_PIX_FMT_YUV420, - .flags = 0, - .mmal = MMAL_ENCODING_I420, - .depth = 12, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 1, - }, - { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .flags = 0, - .mmal = MMAL_ENCODING_YUYV, - .depth = 16, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 2, - }, - { - .name = "RGB24 (LE)", - .fourcc = V4L2_PIX_FMT_RGB24, - .flags = 0, - .mmal = MMAL_ENCODING_RGB24, - .depth = 24, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 3, - }, - { - .name = "JPEG", - .fourcc = V4L2_PIX_FMT_JPEG, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal = MMAL_ENCODING_JPEG, - .depth = 8, - .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE, - .ybbp = 0, - }, - { - .name = "H264", - .fourcc = V4L2_PIX_FMT_H264, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal = MMAL_ENCODING_H264, - .depth = 8, - .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, - .ybbp = 0, - }, - { - .name = "MJPEG", - .fourcc = V4L2_PIX_FMT_MJPEG, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal = MMAL_ENCODING_MJPEG, - .depth = 8, - .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, - .ybbp = 0, - }, - { - .name = "4:2:2, packed, YVYU", - .fourcc = V4L2_PIX_FMT_YVYU, - .flags = 0, - .mmal = MMAL_ENCODING_YVYU, - .depth = 16, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 2, - }, - { - .name = "4:2:2, packed, VYUY", - .fourcc = V4L2_PIX_FMT_VYUY, - .flags = 0, - .mmal = MMAL_ENCODING_VYUY, - .depth = 16, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 2, - }, - { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .flags = 0, - .mmal = MMAL_ENCODING_UYVY, - .depth = 16, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 2, - }, - { - .name = "4:2:0, planar, NV12", - .fourcc = V4L2_PIX_FMT_NV12, - .flags = 0, - .mmal = MMAL_ENCODING_NV12, - .depth = 12, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 1, - }, - { - .name = "RGB24 (BE)", - .fourcc = V4L2_PIX_FMT_BGR24, - .flags = 0, - .mmal = MMAL_ENCODING_BGR24, - .depth = 24, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 3, - }, - { - .name = "4:2:0, planar, YVU", - .fourcc = V4L2_PIX_FMT_YVU420, - .flags = 0, - .mmal = MMAL_ENCODING_YV12, - .depth = 12, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 1, - }, - { - .name = "4:2:0, planar, NV21", - .fourcc = V4L2_PIX_FMT_NV21, - .flags = 0, - .mmal = MMAL_ENCODING_NV21, - .depth = 12, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 1, - }, - { - .name = "RGB32 (BE)", - .fourcc = V4L2_PIX_FMT_BGR32, - .flags = 0, - .mmal = MMAL_ENCODING_BGRA, - .depth = 32, - .mmal_component = MMAL_COMPONENT_CAMERA, - .ybbp = 4, - }, + .name = "4:2:0, planar, YUV", + .fourcc = V4L2_PIX_FMT_YUV420, + .flags = 0, + .mmal = MMAL_ENCODING_I420, + .depth = 12, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 1, + .remove_padding = 1, + }, { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .flags = 0, + .mmal = MMAL_ENCODING_YUYV, + .depth = 16, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 2, + .remove_padding = 0, + }, { + .name = "RGB24 (LE)", + .fourcc = V4L2_PIX_FMT_RGB24, + .flags = 0, + .mmal = MMAL_ENCODING_RGB24, + .depth = 24, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 3, + .remove_padding = 0, + }, { + .name = "JPEG", + .fourcc = V4L2_PIX_FMT_JPEG, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal = MMAL_ENCODING_JPEG, + .depth = 8, + .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE, + .ybbp = 0, + .remove_padding = 0, + }, { + .name = "H264", + .fourcc = V4L2_PIX_FMT_H264, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal = MMAL_ENCODING_H264, + .depth = 8, + .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, + .ybbp = 0, + .remove_padding = 0, + }, { + .name = "MJPEG", + .fourcc = V4L2_PIX_FMT_MJPEG, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal = MMAL_ENCODING_MJPEG, + .depth = 8, + .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, + .ybbp = 0, + .remove_padding = 0, + }, { + .name = "4:2:2, packed, YVYU", + .fourcc = V4L2_PIX_FMT_YVYU, + .flags = 0, + .mmal = MMAL_ENCODING_YVYU, + .depth = 16, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 2, + .remove_padding = 0, + }, { + .name = "4:2:2, packed, VYUY", + .fourcc = V4L2_PIX_FMT_VYUY, + .flags = 0, + .mmal = MMAL_ENCODING_VYUY, + .depth = 16, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 2, + .remove_padding = 0, + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .flags = 0, + .mmal = MMAL_ENCODING_UYVY, + .depth = 16, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 2, + .remove_padding = 0, + }, { + .name = "4:2:0, planar, NV12", + .fourcc = V4L2_PIX_FMT_NV12, + .flags = 0, + .mmal = MMAL_ENCODING_NV12, + .depth = 12, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 1, + .remove_padding = 1, + }, { + .name = "RGB24 (BE)", + .fourcc = V4L2_PIX_FMT_BGR24, + .flags = 0, + .mmal = MMAL_ENCODING_BGR24, + .depth = 24, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 3, + .remove_padding = 0, + }, { + .name = "4:2:0, planar, YVU", + .fourcc = V4L2_PIX_FMT_YVU420, + .flags = 0, + .mmal = MMAL_ENCODING_YV12, + .depth = 12, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 1, + .remove_padding = 1, + }, { + .name = "4:2:0, planar, NV21", + .fourcc = V4L2_PIX_FMT_NV21, + .flags = 0, + .mmal = MMAL_ENCODING_NV21, + .depth = 12, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 1, + .remove_padding = 1, + }, { + .name = "RGB32 (BE)", + .fourcc = V4L2_PIX_FMT_BGR32, + .flags = 0, + .mmal = MMAL_ENCODING_BGRA, + .depth = 32, + .mmal_component = MMAL_COMPONENT_CAMERA, + .ybbp = 4, + .remove_padding = 0, + }, }; static struct mmal_fmt *get_format(struct v4l2_format *f) @@ -245,8 +247,10 @@ static int queue_setup(struct vb2_queue *vq, return -EINVAL; } - if (*nbuffers < (dev->capture.port->current_buffer.num + 2)) - *nbuffers = (dev->capture.port->current_buffer.num + 2); + if (*nbuffers < dev->capture.port->minimum_buffer.num) + *nbuffers = dev->capture.port->minimum_buffer.num; + + dev->capture.port->current_buffer.num = *nbuffers; *nplanes = 1; @@ -263,16 +267,30 @@ static int queue_setup(struct vb2_queue *vq, return 0; } +static int buffer_init(struct vb2_buffer *vb) +{ + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); + struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n", + __func__, dev, vb); + buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0); + + return mmal_vchi_buffer_init(dev->instance, buf); +} + static int buffer_prepare(struct vb2_buffer *vb) { struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); unsigned long size; - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n", - __func__, dev); + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n", + __func__, dev, vb); - BUG_ON(!dev->capture.port); - BUG_ON(!dev->capture.fmt); + if (!dev->capture.port || !dev->capture.fmt) + return -ENODEV; size = dev->capture.stride * dev->capture.height; if (vb2_plane_size(vb, 0) < size) { @@ -285,6 +303,17 @@ static int buffer_prepare(struct vb2_buffer *vb) return 0; } +static void buffer_cleanup(struct vb2_buffer *vb) +{ + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); + struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n", + __func__, dev, vb); + mmal_vchi_buffer_cleanup(buf); +} + static inline bool is_capturing(struct bm2835_mmal_dev *dev) { return dev->capture.camera_port == @@ -450,10 +479,8 @@ static void buffer_queue(struct vb2_buffer *vb) int ret; v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, - "%s: dev:%p buf:%p\n", __func__, dev, buf); - - buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0); + "%s: dev:%p buf:%p, idx %u\n", + __func__, dev, buf, vb2->vb2_buf.index); ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf); if (ret < 0) @@ -465,7 +492,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq); int ret; - int parameter_size; + u32 parameter_size; v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n", __func__, dev); @@ -617,7 +644,9 @@ static void bm2835_mmal_unlock(struct vb2_queue *vq) static const struct vb2_ops bm2835_mmal_video_qops = { .queue_setup = queue_setup, + .buf_init = buffer_init, .buf_prepare = buffer_prepare, + .buf_cleanup = buffer_cleanup, .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, @@ -634,17 +663,19 @@ static int set_overlay_params(struct bm2835_mmal_dev *dev, struct vchiq_mmal_port *port) { struct mmal_parameter_displayregion prev_config = { - .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_ALPHA | - MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN, - .layer = PREVIEW_LAYER, - .alpha = dev->overlay.global_alpha, - .fullscreen = 0, - .dest_rect = { - .x = dev->overlay.w.left, - .y = dev->overlay.w.top, - .width = dev->overlay.w.width, - .height = dev->overlay.w.height, - }, + .set = MMAL_DISPLAY_SET_LAYER | + MMAL_DISPLAY_SET_ALPHA | + MMAL_DISPLAY_SET_DEST_RECT | + MMAL_DISPLAY_SET_FULLSCREEN, + .layer = PREVIEW_LAYER, + .alpha = dev->overlay.global_alpha, + .fullscreen = 0, + .dest_rect = { + .x = dev->overlay.w.left, + .y = dev->overlay.w.top, + .width = dev->overlay.w.width, + .height = dev->overlay.w.height, + }, }; return vchiq_mmal_port_parameter_set(dev->instance, port, MMAL_PARAMETER_DISPLAYREGION, @@ -662,7 +693,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, fmt = &formats[f->index]; - strlcpy(f->description, fmt->name, sizeof(f->description)); + strlcpy((char *)f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; f->flags = fmt->flags; @@ -820,7 +851,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return -EINVAL; inp->type = V4L2_INPUT_TYPE_CAMERA; - sprintf(inp->name, "Camera %u", inp->index); + sprintf((char *)inp->name, "Camera %u", inp->index); return 0; } @@ -848,11 +879,11 @@ static int vidioc_querycap(struct file *file, void *priv, vchiq_mmal_version(dev->instance, &major, &minor); - strcpy(cap->driver, "bm2835 mmal"); - snprintf(cap->card, sizeof(cap->card), "mmal service %d.%d", + strcpy((char *)cap->driver, "bm2835 mmal"); + snprintf((char *)cap->card, sizeof(cap->card), "mmal service %d.%d", major, minor); - snprintf(cap->bus_info, sizeof(cap->bus_info), + snprintf((char *)cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev->v4l2_dev.name); cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; @@ -871,7 +902,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, fmt = &formats[f->index]; - strlcpy(f->description, fmt->name, sizeof(f->description)); + strlcpy((char *)f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; f->flags = fmt->flags; @@ -928,9 +959,19 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, &f->fmt.pix.height, MIN_HEIGHT, dev->max_height, 1, 0); f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp; + if (!mfmt->remove_padding) { + int align_mask = ((32 * mfmt->depth) >> 3) - 1; + /* GPU isn't removing padding, so stride is aligned to 32 */ + f->fmt.pix.bytesperline = + (f->fmt.pix.bytesperline + align_mask) & ~align_mask; + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "Not removing padding, so bytes/line = %d, " + "(align_mask %d)\n", + f->fmt.pix.bytesperline, align_mask); + } /* Image buffer has to be padded to allow for alignment, even though - * we then remove that padding before delivering the buffer. + * we sometimes then remove that padding before delivering the buffer. */ f->fmt.pix.sizeimage = ((f->fmt.pix.height + 15) & ~15) * (((f->fmt.pix.width + 31) & ~31) * mfmt->depth) >> 3; @@ -963,8 +1004,10 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, struct vchiq_mmal_port *port = NULL, *camera_port = NULL; struct vchiq_mmal_component *encode_component = NULL; struct mmal_fmt *mfmt = get_format(f); + u32 remove_padding; - BUG_ON(!mfmt); + if (!mfmt) + return -EINVAL; if (dev->capture.encode_component) { v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, @@ -1031,6 +1074,12 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, camera_port->format.encoding = MMAL_ENCODING_RGB24; } + remove_padding = mfmt->remove_padding; + vchiq_mmal_port_parameter_set(dev->instance, + camera_port, + MMAL_PARAMETER_NO_IMAGE_PADDING, + &remove_padding, sizeof(remove_padding)); + camera_port->format.encoding_variant = 0; camera_port->es.video.width = f->fmt.pix.width; camera_port->es.video.height = f->fmt.pix.height; @@ -1348,7 +1397,6 @@ static int vidioc_s_parm(struct file *file, void *priv, { struct bm2835_mmal_dev *dev = video_drvdata(file); struct v4l2_fract tpf; - struct mmal_parameter_rational fps_param; if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1365,10 +1413,6 @@ static int vidioc_s_parm(struct file *file, void *priv, parm->parm.capture.readbuffers = 1; parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - fps_param.num = 0; /* Select variable fps, and then use - * FPS_RANGE to select the actual limits. - */ - fps_param.den = 1; set_framerate_params(dev); return 0; @@ -1445,7 +1489,7 @@ static int get_num_cameras(struct vchiq_mmal_instance *instance, int ret; struct vchiq_mmal_component *cam_info_component; struct mmal_parameter_camera_info_t cam_info = {0}; - int param_size = sizeof(cam_info); + u32 param_size = sizeof(cam_info); int i; /* create a camera_info component */ @@ -1504,13 +1548,12 @@ static int set_camera_parameters(struct vchiq_mmal_instance *instance, #define MAX_SUPPORTED_ENCODINGS 20 /* MMAL instance and component init */ -static int __init mmal_init(struct bm2835_mmal_dev *dev) +static int mmal_init(struct bm2835_mmal_dev *dev) { int ret; struct mmal_es_format_local *format; - u32 bool_true = 1; u32 supported_encodings[MAX_SUPPORTED_ENCODINGS]; - int param_size; + u32 param_size; struct vchiq_mmal_component *camera; ret = vchiq_mmal_init(&dev->instance); @@ -1592,11 +1635,6 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) format->es->video.frame_rate.num = 0; /* Rely on fps_range */ format->es->video.frame_rate.den = 1; - vchiq_mmal_port_parameter_set(dev->instance, - &camera->output[MMAL_CAMERA_PORT_VIDEO], - MMAL_PARAMETER_NO_IMAGE_PADDING, - &bool_true, sizeof(bool_true)); - format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format; format->encoding = MMAL_ENCODING_OPAQUE; @@ -1618,11 +1656,6 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; - vchiq_mmal_port_parameter_set(dev->instance, - &camera->output[MMAL_CAMERA_PORT_CAPTURE], - MMAL_PARAMETER_NO_IMAGE_PADDING, - &bool_true, sizeof(bool_true)); - /* get the preview component ready */ ret = vchiq_mmal_component_init( dev->instance, "ril.video_render", @@ -1723,8 +1756,8 @@ unreg_mmal: return ret; } -static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, - struct video_device *vfd) +static int bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, + struct video_device *vfd) { int ret; @@ -1803,7 +1836,7 @@ static struct v4l2_format default_v4l2_format = { .fmt.pix.sizeimage = 1024 * 768, }; -static int __init bm2835_mmal_init(void) +static int bcm2835_mmal_probe(struct platform_device *pdev) { int ret; struct bm2835_mmal_dev *dev; @@ -1923,7 +1956,7 @@ cleanup_gdev: return ret; } -static void __exit bm2835_mmal_exit(void) +static int bcm2835_mmal_remove(struct platform_device *pdev) { int camera; struct vchiq_mmal_instance *instance = gdev[0]->instance; @@ -1933,7 +1966,16 @@ static void __exit bm2835_mmal_exit(void) gdev[camera] = NULL; } vchiq_mmal_finalise(instance); + + return 0; } -module_init(bm2835_mmal_init); -module_exit(bm2835_mmal_exit); +static struct platform_driver bcm2835_camera_driver = { + .probe = bcm2835_mmal_probe, + .remove = bcm2835_mmal_remove, + .driver = { + .name = "bcm2835-camera", + }, +}; + +module_platform_driver(bcm2835_camera_driver) |