diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index 8553b677eb080937d54a902f18d859dceb4808b6..c5ca564141398e16f1a11c384c8720c62f55d974 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -299,8 +299,8 @@ 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); @@ -492,7 +492,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); + "%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) diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c index 0f1961aeb223bc0ffa461bff427ab83eb7403c8e..3a3b843fc1229c24f751a0e30f1d2fcebbd83171 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c @@ -326,16 +326,12 @@ static int bulk_receive(struct vchiq_mmal_instance *instance, struct mmal_msg_context *msg_context) { unsigned long rd_len; - unsigned long flags = 0; int ret; rd_len = msg->u.buffer_from_host.buffer_header.length; - /* take buffer from queue */ - spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags); - if (list_empty(&msg_context->u.bulk.port->buffers)) { - spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags); - pr_err("buffer list empty trying to submit bulk receive\n"); + if (!msg_context->u.bulk.buffer) { + pr_err("bulk.buffer not configured - error in buffer_from_host\n"); /* todo: this is a serious error, we should never have * committed a buffer_to_host operation to the mmal @@ -350,13 +346,6 @@ static int bulk_receive(struct vchiq_mmal_instance *instance, return -EINVAL; } - msg_context->u.bulk.buffer = - list_entry(msg_context->u.bulk.port->buffers.next, - struct mmal_buffer, list); - list_del(&msg_context->u.bulk.buffer->list); - - spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags); - /* ensure we do not overrun the available buffer */ if (rd_len > msg_context->u.bulk.buffer->buffer_size) { rd_len = msg_context->u.bulk.buffer->buffer_size; @@ -419,31 +408,6 @@ static int inline_receive(struct vchiq_mmal_instance *instance, struct mmal_msg *msg, struct mmal_msg_context *msg_context) { - unsigned long flags = 0; - - /* take buffer from queue */ - spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags); - if (list_empty(&msg_context->u.bulk.port->buffers)) { - spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags); - pr_err("buffer list empty trying to receive inline\n"); - - /* todo: this is a serious error, we should never have - * committed a buffer_to_host operation to the mmal - * port without the buffer to back it up (with - * underflow handling) and there is no obvious way to - * deal with this. Less bad than the bulk case as we - * can just drop this on the floor but...unhelpful - */ - return -EINVAL; - } - - msg_context->u.bulk.buffer = - list_entry(msg_context->u.bulk.port->buffers.next, - struct mmal_buffer, list); - list_del(&msg_context->u.bulk.buffer->list); - - spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags); - memcpy(msg_context->u.bulk.buffer->buffer, msg->u.buffer_from_host.short_data, msg->u.buffer_from_host.payload_in_message); @@ -463,6 +427,9 @@ buffer_from_host(struct vchiq_mmal_instance *instance, struct mmal_msg m; int ret; + if (!port->enabled) + return -EINVAL; + pr_debug("instance:%p buffer:%p\n", instance->handle, buf); /* get context */ @@ -476,7 +443,7 @@ buffer_from_host(struct vchiq_mmal_instance *instance, /* store bulk message context for when data arrives */ msg_context->u.bulk.instance = instance; msg_context->u.bulk.port = port; - msg_context->u.bulk.buffer = NULL; /* not valid until bulk xfer */ + msg_context->u.bulk.buffer = buf; msg_context->u.bulk.buffer_used = 0; /* initialise work structure ready to schedule callback */ @@ -526,43 +493,6 @@ buffer_from_host(struct vchiq_mmal_instance *instance, return ret; } -/* submit a buffer to the mmal sevice - * - * the buffer_from_host uses size data from the ports next available - * mmal_buffer and deals with there being no buffer available by - * incrementing the underflow for later - */ -static int port_buffer_from_host(struct vchiq_mmal_instance *instance, - struct vchiq_mmal_port *port) -{ - int ret; - struct mmal_buffer *buf; - unsigned long flags = 0; - - if (!port->enabled) - return -EINVAL; - - /* peek buffer from queue */ - spin_lock_irqsave(&port->slock, flags); - if (list_empty(&port->buffers)) { - spin_unlock_irqrestore(&port->slock, flags); - return -ENOSPC; - } - - buf = list_entry(port->buffers.next, struct mmal_buffer, list); - - spin_unlock_irqrestore(&port->slock, flags); - - /* issue buffer to mmal service */ - ret = buffer_from_host(instance, port, buf); - if (ret) { - pr_err("adding buffer header failed\n"); - /* todo: how should this be dealt with */ - } - - return ret; -} - /* deals with receipt of buffer to host message */ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, struct mmal_msg *msg, u32 msg_len) @@ -1420,7 +1350,14 @@ static int port_disable(struct vchiq_mmal_instance *instance, ret = port_action_port(instance, port, MMAL_MSG_PORT_ACTION_TYPE_DISABLE); if (ret == 0) { - /* drain all queued buffers on port */ + /* + * Drain all queued buffers on port. This should only + * apply to buffers that have been queued before the port + * has been enabled. If the port has been enabled and buffers + * passed, then the buffers should have been removed from this + * list, and we should get the relevant callbacks via VCHIQ + * to release the buffers. + */ spin_lock_irqsave(&port->slock, flags); list_for_each_safe(buf_head, q, &port->buffers) { @@ -1449,7 +1386,7 @@ static int port_enable(struct vchiq_mmal_instance *instance, struct vchiq_mmal_port *port) { unsigned int hdr_count; - struct list_head *buf_head; + struct list_head *q, *buf_head; int ret; if (port->enabled) @@ -1475,7 +1412,7 @@ static int port_enable(struct vchiq_mmal_instance *instance, if (port->buffer_cb) { /* send buffer headers to videocore */ hdr_count = 1; - list_for_each(buf_head, &port->buffers) { + list_for_each_safe(buf_head, q, &port->buffers) { struct mmal_buffer *mmalbuf; mmalbuf = list_entry(buf_head, struct mmal_buffer, @@ -1484,6 +1421,7 @@ static int port_enable(struct vchiq_mmal_instance *instance, if (ret) goto done; + list_del(buf_head); hdr_count++; if (hdr_count > port->current_buffer.num) break; @@ -1696,12 +1634,15 @@ int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, struct mmal_buffer *buffer) { unsigned long flags = 0; + int ret; - spin_lock_irqsave(&port->slock, flags); - list_add_tail(&buffer->list, &port->buffers); - spin_unlock_irqrestore(&port->slock, flags); - - port_buffer_from_host(instance, port); + ret = buffer_from_host(instance, port, buffer); + if (ret == -EINVAL) { + /* Port is disabled. Queue for when it is enabled. */ + spin_lock_irqsave(&port->slock, flags); + list_add_tail(&buffer->list, &port->buffers); + spin_unlock_irqrestore(&port->slock, flags); + } return 0; }