drivers/media/platform/samsung/s3c-camif/camif-capture.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/samsung/s3c-camif/camif-capture.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/samsung/s3c-camif/camif-capture.c
Extension
.c
Size
43072 bytes
Lines
1650
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (vp->state & ST_VP_OFF) {
			/* Last IRQ */
			vp->state &= ~(ST_VP_OFF | ST_VP_ABORTING |
				       ST_VP_LASTIRQ);
			wake_up(&vp->irq_queue);
			goto unlock;
		} else if (vp->state & ST_VP_LASTIRQ) {
			camif_hw_disable_capture(vp);
			camif_hw_enable_scaler(vp, false);
			camif_hw_set_lastirq(vp, false);
			vp->state |= ST_VP_OFF;
		} else {
			/* Disable capture, enable last IRQ */
			camif_hw_set_lastirq(vp, true);
			vp->state |= ST_VP_LASTIRQ;
		}
	}

	if (!list_empty(&vp->pending_buf_q) && (vp->state & ST_VP_RUNNING) &&
	    !list_empty(&vp->active_buf_q)) {
		unsigned int index;
		struct camif_buffer *vbuf;
		/*
		 * Get previous DMA write buffer index:
		 * 0 => DMA buffer 0, 2;
		 * 1 => DMA buffer 1, 3.
		 */
		index = (CISTATUS_FRAMECNT(status) + 2) & 1;
		vbuf = camif_active_queue_peek(vp, index);

		if (!WARN_ON(vbuf == NULL)) {
			/* Dequeue a filled buffer */
			vbuf->vb.vb2_buf.timestamp = ktime_get_ns();
			vbuf->vb.sequence = vp->frame_sequence++;
			vb2_buffer_done(&vbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);

			/* Set up an empty buffer at the DMA engine */
			vbuf = camif_pending_queue_pop(vp);
			vbuf->index = index;
			camif_hw_set_output_addr(vp, &vbuf->paddr, index);
			camif_hw_set_output_addr(vp, &vbuf->paddr, index + 2);

			/* Scheduled in H/W, add to the queue */
			camif_active_queue_add(vp, vbuf);
		}
	} else if (!(vp->state & ST_VP_ABORTING) &&
		   (vp->state & ST_VP_PENDING))  {
		vp->state |= ST_VP_RUNNING;
	}

	if (vp->state & ST_VP_CONFIG) {
		camif_prepare_dma_offset(vp);
		camif_hw_set_camera_crop(camif);
		camif_hw_set_scaler(vp);
		camif_hw_set_flip(vp);
		camif_hw_set_test_pattern(camif, camif->test_pattern);
		if (camif->variant->has_img_effect)
			camif_hw_set_effect(camif, camif->colorfx,
				    camif->colorfx_cr, camif->colorfx_cb);
		vp->state &= ~ST_VP_CONFIG;
	}
unlock:
	spin_unlock(&camif->slock);
	return IRQ_HANDLED;
}

static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
	struct camif_vp *vp = vb2_get_drv_priv(vq);
	struct camif_dev *camif = vp->camif;
	unsigned long flags;
	int ret;

	/*
	 * We assume the codec capture path is always activated
	 * first, before the preview path starts streaming.
	 * This is required to avoid internal FIFO overflow and
	 * a need for CAMIF software reset.
	 */
	spin_lock_irqsave(&camif->slock, flags);

	if (camif->stream_count == 0) {
		camif_hw_reset(camif);
		ret = s3c_camif_hw_init(camif, vp);
	} else {
		ret = s3c_camif_hw_vp_init(camif, vp);
	}
	spin_unlock_irqrestore(&camif->slock, flags);

	if (ret < 0) {

Annotation

Implementation Notes