/* * Cancel the video buffers queue. * * Cancelling the queue marks all buffers on the irq queue as erroneous, * wakes them up and removes them from the queue. * * If the disconnect parameter is set, further calls to uvc_queue_buffer will * fail with -ENODEV. * * This function acquires the irq spinlock and can be called from interrupt * context. */ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) { struct uvc_buffer *buf; unsigned long flags; spin_lock_irqsave(&queue->irqlock, flags); while (!list_empty(&queue->irqqueue)) { buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, queue); list_del(&buf->queue); buf->state = UVC_BUF_STATE_ERROR; vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); } /* This must be protected by the irqlock spinlock to avoid race * conditions between uvc_buffer_queue and the disconnection event that * could result in an interruptible wait in uvc_dequeue_buffer. Do not * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED * state outside the queue code. */ if (disconnect) queue->flags |= UVC_QUEUE_DISCONNECTED; spin_unlock_irqrestore(&queue->irqlock, flags); }
/* Called from the IPU IDMAC ISR */ static void mx3_cam_dma_done(void *arg) { struct idmac_tx_desc *desc = to_tx_desc(arg); struct dma_chan *chan = desc->txd.chan; struct idmac_channel *ichannel = to_idmac_chan(chan); struct mx3_camera_dev *mx3_cam = ichannel->client; dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0); spin_lock(&mx3_cam->lock); if (mx3_cam->active) { struct vb2_buffer *vb = &mx3_cam->active->vb; struct mx3_camera_buffer *buf = to_mx3_vb(vb); list_del_init(&buf->queue); do_gettimeofday(&vb->v4l2_buf.timestamp); vb->v4l2_buf.field = mx3_cam->field; vb->v4l2_buf.sequence = mx3_cam->sequence++; vb2_buffer_done(vb, VB2_BUF_STATE_DONE); } if (list_empty(&mx3_cam->capture)) { mx3_cam->active = NULL; spin_unlock(&mx3_cam->lock); /* * stop capture - without further buffers IPU_CHA_BUF0_RDY will * not get updated */ return; } mx3_cam->active = list_entry(mx3_cam->capture.next, struct mx3_camera_buffer, queue); spin_unlock(&mx3_cam->lock); }
static int fthd_start_streaming(struct vb2_queue *vq, unsigned int count) { struct fthd_private *dev_priv = vb2_get_drv_priv(vq); struct h2t_buf_ctx *ctx; int i, ret; pr_debug("count = %d\n", count); ret = fthd_start_channel(dev_priv, 0); if (ret) return ret; for(i = 0; i < FTHD_BUFFERS && count; i++, count--) { ctx = dev_priv->h2t_bufs + i; if (ctx->state != BUF_DRV_QUEUED) continue; if (fthd_send_h2t_buffer(dev_priv, ctx)) { vb2_buffer_done(ctx->vb, VB2_BUF_STATE_ERROR); ctx->state = BUF_ALLOC; } ctx->state = BUF_HW_QUEUED; } return 0; }
static int trigger_dma_transfer_to_buf(struct cssp_cam_dev *dev, struct vb2_buffer *vb) { dma_addr_t dma_buf = vb2_dma_contig_plane_dma_addr(vb, 0); if (!dma_buf) { /* Is this possible? Release the vb2_buffer with an error here, */ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); dev->current_vb = NULL; return -ENOMEM; } dev->dma_tr_params.dst = dma_buf; // Enable DMA edma_write_slot(dev->dma_ch, &dev->dma_tr_params); dev->current_vb = vb; // Enable data capture dev->mode |= ENABLE; writew(dev->mode, dev->reg_base_virt + REG_MODE); return 0; }
void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; struct timeval *tv; struct timespec ts; if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { wake_up(&fimc->irq_queue); goto done; } if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) { ktime_get_real_ts(&ts); v_buf = fimc_active_queue_pop(cap); tv = &v_buf->vb.v4l2_buf.timestamp; tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; v_buf->vb.v4l2_buf.sequence = cap->frame_count++; vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } if (!list_empty(&cap->pending_buf_q)) { v_buf = fimc_pending_queue_pop(cap); fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); v_buf->index = cap->buf_index; /* Move the buffer to the capture active queue */ fimc_active_queue_add(cap, v_buf); dbg("next frame: %d, done frame: %d", fimc_hw_get_frame_index(fimc), v_buf->index); if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } if (cap->active_buf_cnt == 0) { if (deq_buf) clear_bit(ST_CAPT_RUN, &fimc->state); if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } else { set_bit(ST_CAPT_RUN, &fimc->state); } if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) fimc_capture_config_update(cap->ctx); done: if (cap->active_buf_cnt == 1) { fimc_deactivate_capture(fimc); clear_bit(ST_CAPT_STREAM, &fimc->state); } dbg("frame: %d, active_buf_cnt: %d", fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); }
/* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. */ static void pwc_isoc_handler(struct urb *urb) { struct pwc_device *pdev = (struct pwc_device *)urb->context; int i, fst, flen; unsigned char *iso_buf = NULL; if (urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN) { PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); return; } if (pdev->fill_buf == NULL) pdev->fill_buf = pwc_get_next_fill_buf(pdev); if (urb->status != 0) { const char *errmsg; errmsg = "Unknown"; switch(urb->status) { case -ENOSR: errmsg = "Buffer error (overrun)"; break; case -EPIPE: errmsg = "Stalled (device not responding)"; break; case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; case -ETIME: errmsg = "Device does not respond"; break; } PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); /* Give up after a number of contiguous errors */ if (++pdev->visoc_errors > MAX_ISOC_ERRORS) { PWC_ERROR("Too many ISOC errors, bailing out.\n"); if (pdev->fill_buf) { vb2_buffer_done(&pdev->fill_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); pdev->fill_buf = NULL; } } pdev->vsync = 0; /* Drop the current frame */ goto handler_end; } /* Reset ISOC error counter. We did get here, after all. */ pdev->visoc_errors = 0; /* vsync: 0 = don't copy data 1 = sync-hunt 2 = synched */ /* Compact data */ for (i = 0; i < urb->number_of_packets; i++) { fst = urb->iso_frame_desc[i].status; flen = urb->iso_frame_desc[i].actual_length; iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (fst != 0) { PWC_ERROR("Iso frame %d has error %d\n", i, fst); continue; } if (flen > 0 && pdev->vsync) { struct pwc_frame_buf *fbuf = pdev->fill_buf; if (pdev->vsync == 1) { fbuf->vb.vb2_buf.timestamp = ktime_get_ns(); pdev->vsync = 2; } if (flen + fbuf->filled > pdev->frame_total_size) { PWC_ERROR("Frame overflow (%d > %d)\n", flen + fbuf->filled, pdev->frame_total_size); pdev->vsync = 0; /* Let's wait for an EOF */ } else { memcpy(fbuf->data + fbuf->filled, iso_buf, flen); fbuf->filled += flen; } } if (flen < pdev->vlast_packet_size) { /* Shorter packet... end of frame */ if (pdev->vsync == 2) pwc_frame_complete(pdev); if (pdev->fill_buf == NULL) pdev->fill_buf = pwc_get_next_fill_buf(pdev); if (pdev->fill_buf) { pdev->fill_buf->filled = 0; pdev->vsync = 1; } } pdev->vlast_packet_size = flen; } handler_end: i = usb_submit_urb(urb, GFP_ATOMIC); if (i != 0) PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); }
static void pwc_frame_complete(struct pwc_device *pdev) { struct pwc_frame_buf *fbuf = pdev->fill_buf; /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus frames on the USB wire after an exposure change. This conditition is however detected in the cam and a bit is set in the header. */ if (pdev->type == 730) { unsigned char *ptr = (unsigned char *)fbuf->data; if (ptr[1] == 1 && ptr[0] & 0x10) { PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n"); pdev->drop_frames += 2; } if ((ptr[0] ^ pdev->vmirror) & 0x01) { pwc_snapshot_button(pdev, ptr[0] & 0x01); } if ((ptr[0] ^ pdev->vmirror) & 0x02) { if (ptr[0] & 0x02) PWC_TRACE("Image is mirrored.\n"); else PWC_TRACE("Image is normal.\n"); } pdev->vmirror = ptr[0] & 0x03; /* Sometimes the trailer of the 730 is still sent as a 4 byte packet after a short frame; this condition is filtered out specifically. A 4 byte frame doesn't make sense anyway. So we get either this sequence: drop_bit set -> 4 byte frame -> short frame -> good frame Or this one: drop_bit set -> short frame -> good frame So we drop either 3 or 2 frames in all! */ if (fbuf->filled == 4) pdev->drop_frames++; } else if (pdev->type == 740 || pdev->type == 720) { unsigned char *ptr = (unsigned char *)fbuf->data; if ((ptr[0] ^ pdev->vmirror) & 0x01) { pwc_snapshot_button(pdev, ptr[0] & 0x01); } pdev->vmirror = ptr[0] & 0x03; } /* In case we were instructed to drop the frame, do so silently. */ if (pdev->drop_frames > 0) { pdev->drop_frames--; } else { /* Check for underflow first */ if (fbuf->filled < pdev->frame_total_size) { PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);" " discarded.\n", fbuf->filled); } else { fbuf->vb.field = V4L2_FIELD_NONE; fbuf->vb.sequence = pdev->vframe_count; vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE); pdev->fill_buf = NULL; pdev->vsync = 0; } } /* !drop_frames */ pdev->vframe_count++; }
/* Called for each 256-byte image chunk. * First word identifies the chunk, followed by 240 words of image * data and padding. */ static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk) { int frame_id, odd, chunk_no; u32 *frame; struct usbtv_buf *buf; unsigned long flags; /* Ignore corrupted lines. */ if (!USBTV_MAGIC_OK(chunk)) return; frame_id = USBTV_FRAME_ID(chunk); odd = USBTV_ODD(chunk); chunk_no = USBTV_CHUNK_NO(chunk); if (chunk_no >= usbtv->n_chunks) return; /* Beginning of a frame. */ if (chunk_no == 0) { usbtv->frame_id = frame_id; usbtv->chunks_done = 0; } if (usbtv->frame_id != frame_id) return; spin_lock_irqsave(&usbtv->buflock, flags); if (list_empty(&usbtv->bufs)) { /* No free buffers. Userspace likely too slow. */ spin_unlock_irqrestore(&usbtv->buflock, flags); return; } /* First available buffer. */ buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); frame = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); /* Copy the chunk data. */ usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd); usbtv->chunks_done++; /* Last chunk in a field */ if (chunk_no == usbtv->n_chunks-1) { /* Last chunk in a frame, signalling an end */ if (odd && !usbtv->last_odd) { int size = vb2_plane_size(&buf->vb.vb2_buf, 0); enum vb2_buffer_state state = usbtv->chunks_done == usbtv->n_chunks ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; buf->vb.field = V4L2_FIELD_INTERLACED; buf->vb.sequence = usbtv->sequence++; buf->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); vb2_buffer_done(&buf->vb.vb2_buf, state); list_del(&buf->list); } usbtv->last_odd = odd; } spin_unlock_irqrestore(&usbtv->buflock, flags); }
int msm_mctl_pp_proc_cmd(struct msm_cam_media_controller *p_mctl, struct msm_mctl_pp_cmd *pp_cmd) { int rc = 0; struct msm_mctl_pp_frame_buffer pp_buffer; struct msm_frame_buffer *buf = NULL; void __user *argp = (void __user *)pp_cmd->value; int msg_type = VFE_MSG_OUTPUT_V; unsigned long flags; switch (pp_cmd->id) { case MCTL_CMD_GET_FRAME_BUFFER: { if (copy_from_user(&pp_buffer, pp_cmd->value, sizeof(pp_buffer))) return -EFAULT; msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path); buf = msm_mctl_get_free_buf(p_mctl, msg_type); pp_buffer.buf_handle = (uint32_t)buf; if (copy_to_user((void *)argp, &pp_buffer, sizeof(struct msm_mctl_pp_frame_buffer))) { ERR_COPY_TO_USER(); rc = -EFAULT; } break; } case MCTL_CMD_PUT_FRAME_BUFFER: { if (copy_from_user(&pp_buffer, pp_cmd->value, sizeof(pp_buffer))) return -EFAULT; msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path); buf = (struct msm_frame_buffer *)pp_buffer.buf_handle; msm_mctl_put_free_buf(p_mctl, msg_type, buf); break; } case MCTL_CMD_DIVERT_FRAME_PP_PATH: { struct msm_mctl_pp_divert_pp divert_pp; if (copy_from_user(&divert_pp, pp_cmd->value, sizeof(divert_pp))) return -EFAULT; D("%s: PP_PATH, path=%d", __func__, divert_pp.path); spin_lock_irqsave(&p_mctl->pp_info.lock, flags); p_mctl->pp_info.pp_ctrl.pp_msg_type = divert_pp.path; spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); D("%s: pp path = %d", __func__, p_mctl->pp_info.pp_ctrl.pp_msg_type); break; } case MCTL_CMD_DIVERT_FRAME_PP_DONE: { struct msm_frame_buffer *buf = NULL; if (copy_from_user(&pp_buffer, pp_cmd->value, sizeof(pp_buffer))) return -EFAULT; buf = (struct msm_frame_buffer *)pp_buffer.buf_handle; msg_type = msm_mctl_pp_path_to_msg_type( pp_buffer.path); if (msm_mctl_buf_del(p_mctl, msg_type, buf) == 0) { vb2_buffer_done(&buf->vidbuf, VB2_BUF_STATE_DONE); } } break; default: rc = -EPERM; break; } return rc; }
/* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object * * Remove the current video buffer from the DMA queue and fill its timestamp and * field count before handing it back to videobuf2. * * For capture video nodes the buffer state is set to VB2_BUF_STATE_DONE if no * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise. * For video output nodes the buffer state is always set to VB2_BUF_STATE_DONE. * * The DMA queue is expected to contain at least one buffer. * * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is * empty. */ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) { struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); enum isp_pipeline_state state; struct isp_buffer *buf; unsigned long flags; spin_lock_irqsave(&video->irqlock, flags); if (WARN_ON(list_empty(&video->dmaqueue))) { spin_unlock_irqrestore(&video->irqlock, flags); return NULL; } buf = list_first_entry(&video->dmaqueue, struct isp_buffer, irqlist); list_del(&buf->irqlist); spin_unlock_irqrestore(&video->irqlock, flags); v4l2_get_timestamp(&buf->vb.timestamp); /* Do frame number propagation only if this is the output video node. * Frame number either comes from the CSI receivers or it gets * incremented here if H3A is not active. * Note: There is no guarantee that the output buffer will finish * first, so the input number might lag behind by 1 in some cases. */ if (video == pipe->output && !pipe->do_propagation) buf->vb.sequence = atomic_inc_return(&pipe->frame_number); else buf->vb.sequence = atomic_read(&pipe->frame_number); if (pipe->field != V4L2_FIELD_NONE) buf->vb.sequence /= 2; buf->vb.field = pipe->field; /* Report pipeline errors to userspace on the capture device side. */ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { state = VB2_BUF_STATE_ERROR; pipe->error = false; } else { state = VB2_BUF_STATE_DONE; } vb2_buffer_done(&buf->vb.vb2_buf, state); spin_lock_irqsave(&video->irqlock, flags); if (list_empty(&video->dmaqueue)) { spin_unlock_irqrestore(&video->irqlock, flags); if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISP_PIPELINE_QUEUE_OUTPUT | ISP_PIPELINE_STREAM; else state = ISP_PIPELINE_QUEUE_INPUT | ISP_PIPELINE_STREAM; spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~state; if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS) video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; spin_unlock_irqrestore(&pipe->lock, flags); return NULL; } if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { spin_lock(&pipe->lock); pipe->state &= ~ISP_PIPELINE_STREAM; spin_unlock(&pipe->lock); } buf = list_first_entry(&video->dmaqueue, struct isp_buffer, irqlist); spin_unlock_irqrestore(&video->irqlock, flags); return buf; }
irqreturn_t vc_handler(struct vcap_dev *dev) { uint32_t irq, timestamp; enum rdy_buf vc_buf_status, buf_ind; struct vcap_buffer *buf; struct vb2_buffer *vb = NULL; struct vcap_client_data *c_data; struct v4l2_event v4l2_evt; irq = readl_relaxed(VCAP_VC_INT_STATUS); dprintk(1, "%s: irq=0x%08x\n", __func__, irq); v4l2_evt.id = 0; if (irq & 0x8000200) { v4l2_evt.type = V4L2_EVENT_PRIVATE_START + VCAP_VC_PIX_ERR_EVENT; v4l2_event_queue(dev->vfd, &v4l2_evt); } if (irq & 0x40000200) { v4l2_evt.type = V4L2_EVENT_PRIVATE_START + VCAP_VC_LINE_ERR_EVENT; v4l2_event_queue(dev->vfd, &v4l2_evt); } if (irq & 0x20000200) { v4l2_evt.type = V4L2_EVENT_PRIVATE_START + VCAP_VC_VSYNC_ERR_EVENT; v4l2_event_queue(dev->vfd, &v4l2_evt); } if (irq & 0x00000800) { v4l2_evt.type = V4L2_EVENT_PRIVATE_START + VCAP_VC_NPL_OFLOW_ERR_EVENT; v4l2_event_queue(dev->vfd, &v4l2_evt); } if (irq & 0x00000400) { v4l2_evt.type = V4L2_EVENT_PRIVATE_START + VCAP_VC_LBUF_OFLOW_ERR_EVENT; v4l2_event_queue(dev->vfd, &v4l2_evt); } vc_buf_status = irq & VC_BUFFER_WRITTEN; dprintk(1, "Done buf status = %d\n", vc_buf_status); if (vc_buf_status == VC_NO_BUF) { writel_relaxed(irq, VCAP_VC_INT_CLEAR); pr_err("VC IRQ shows some error\n"); return IRQ_HANDLED; } if (dev->vc_client == NULL) { writel_relaxed(irq, VCAP_VC_INT_CLEAR); pr_err("VC: There is no active vc client\n"); return IRQ_HANDLED; } c_data = dev->vc_client; spin_lock(&dev->vc_client->cap_slock); if (list_empty(&dev->vc_client->vid_vc_action.active)) { /* Just leave we have no new queued buffers */ spin_unlock(&dev->vc_client->cap_slock); writel_relaxed(irq, VCAP_VC_INT_CLEAR); v4l2_evt.type = V4L2_EVENT_PRIVATE_START + VCAP_VC_BUF_OVERWRITE_EVENT; v4l2_event_queue(dev->vfd, &v4l2_evt); dprintk(1, "We have no more avilable buffers\n"); return IRQ_HANDLED; } spin_unlock(&dev->vc_client->cap_slock); timestamp = readl_relaxed(VCAP_VC_TIMESTAMP); buf_ind = dev->vc_client->vid_vc_action.buf_ind; if (vc_buf_status == VC_BUF1N2) { /* There are 2 buffer ready */ writel_relaxed(irq, VCAP_VC_INT_CLEAR); return IRQ_HANDLED; } else if (buf_ind != vc_buf_status) { /* buffer is out of sync */ writel_relaxed(irq, VCAP_VC_INT_CLEAR); return IRQ_HANDLED; } if (buf_ind == VC_BUF1) { dprintk(1, "Got BUF1\n"); vb = &dev->vc_client->vid_vc_action.buf1->vb; spin_lock(&dev->vc_client->cap_slock); if (list_empty(&dev->vc_client->vid_vc_action.active)) { spin_unlock(&dev->vc_client->cap_slock); v4l2_evt.type = V4L2_EVENT_PRIVATE_START + VCAP_VC_BUF_OVERWRITE_EVENT; v4l2_event_queue(dev->vfd, &v4l2_evt); writel_relaxed(irq, VCAP_VC_INT_CLEAR); return IRQ_HANDLED; } buf = list_entry(dev->vc_client->vid_vc_action.active.next, struct vcap_buffer, list); list_del(&buf->list); spin_unlock(&dev->vc_client->cap_slock); /* Config vc with this new buffer */ config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1, VCAP_VC_C_ADDR_1); vb->v4l2_buf.timestamp.tv_usec = timestamp; vb2_buffer_done(vb, VB2_BUF_STATE_DONE); dev->vc_client->vid_vc_action.buf1 = buf; dev->vc_client->vid_vc_action.buf_ind = VC_BUF2; irq = VC_BUF1; } else {
static irqreturn_t unicam_camera_isr(int irq, void *arg) { struct unicam_camera_dev *unicam_dev = (struct unicam_camera_dev *)arg; unsigned int status; unsigned int reg_status; int ret; CSL_CAM_BUFFER_STATUS_st_t bufStatus; unsigned int bytes_used; unsigned long flags; static unsigned int t1 = 0, t2 = 0, fps = 0; spin_lock_irqsave(&unicam_dev->lock, flags); if (!unicam_dev->streaming) { pr_err("Interrupt triggered after stopping camera!\n"); spin_unlock_irqrestore(&unicam_dev->lock, flags); return IRQ_HANDLED; } else { spin_unlock_irqrestore(&unicam_dev->lock, flags); } /* has the interrupt occured for Channel 0? */ reg_status = csl_cam_get_rx_status(unicam_dev->cslCamHandle, (CSL_CAM_RX_STATUS_t *) &status); dprintk("received unicam interrupt reg_status=0x%x status=0x%x\n", reg_status, status); if (status & CSL_CAM_RX_INT) { /* get and clear interrupt status */ reg_status = csl_cam_get_intr_status(unicam_dev->cslCamHandle, (CSL_CAM_INTERRUPT_t *) &status); if (status & CSL_CAM_INT_FRAME_START) { status = status & ~CSL_CAM_INT_FRAME_START; if (reg_status & 0x2000) pr_err("Camera: Urgent request was signalled at FS!!!\n"); } if ((status & CSL_CAM_INT_FRAME_END) || (status & CSL_CAM_INT_LINE_COUNT)) { struct vb2_buffer *vb = unicam_dev->active; status &= ~(CSL_CAM_INT_FRAME_END | CSL_CAM_INT_LINE_COUNT); fps++; if (reg_status & 0x2000) pr_err("Camera: Urgent request was signalled at FE!!!!\n"); if (t1 == 0 && t2 == 0) t1 = t2 = jiffies_to_msecs(jiffies); t2 = jiffies_to_msecs(jiffies); if (t2 - t1 > 1000) { printk(" sensor fps = %d \n", fps); fps = 0; t1 = t2; } dprintk("frame received"); /* csl_cam_register_display(unicam_dev->cslCamHandle);*/ if (!vb) goto out; /* mark the buffer done */ /* queue another buffer and trigger capture */ if (likely(unicam_dev->skip_frames <= 0)) { spin_lock_irqsave(&unicam_dev->lock, flags); list_del_init(&to_unicam_camera_vb(vb)->queue); spin_unlock_irqrestore(&unicam_dev->lock, flags); do_gettimeofday(&vb->v4l2_buf.timestamp); vb->v4l2_planes[0].bytesused = 0; if (unicam_dev->icd->current_fmt->code == V4L2_MBUS_FMT_JPEG_1X8) { ret = csl_cam_get_buffer_status (unicam_dev->cslCamHandle, CSL_CAM_DATA, &bufStatus); if (ret == CSL_CAM_OK) { bytes_used = (bufStatus.write_ptr - bufStatus.buffer_st. start_addr); vb->v4l2_planes[0].bytesused = bytes_used; } else dev_warn(unicam_dev->dev, "%s:failed to get buffer status", __func__); } else { ret = csl_cam_get_buffer_status (unicam_dev->cslCamHandle, CSL_CAM_IMAGE, &bufStatus); if (ret == CSL_CAM_OK) { dprintk("Buffer Status:"); dprintk("addr:0x%x size:0x%x" "ls:%d wp:0x%x" "ppl:%d lpf:%d", bufStatus.buffer_st. start_addr, bufStatus.buffer_st. size, bufStatus.buffer_st. line_stride, bufStatus.write_ptr, bufStatus. bytes_per_line, bufStatus. lines_per_frame); } } vb2_buffer_done(vb, VB2_BUF_STATE_DONE); spin_lock_irqsave(&unicam_dev->lock, flags); if (unicam_dev->stopping) { up(&unicam_dev->stop_sem); unicam_dev->active = NULL; } else if (!list_empty(&unicam_dev->capture)) { unicam_dev->active = &list_entry(unicam_dev-> capture.next, struct unicam_camera_buffer, queue)->vb; } else {
static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv, struct vb2_buffer *vb) { dma_addr_t buffer = vb2_dma_contig_plane_paddr(vb, 0); void *vaddr = vb2_plane_vaddr(vb, 0); struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur; /* XXX: format dependant */ size_t offset_dmadesc = ALIGN(pix->width * pix->height + ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32); u32 *dmadesc = vaddr + offset_dmadesc; u32 heocher; if (priv->cfgstate == at91sam9x5_video_CFG_GOOD_LATCH) { heocher = REG_HEOCHER_UPDATEEN; priv->cfgstate = at91sam9x5_video_CFG_GOOD; } else { BUG_ON(priv->cfgstate != at91sam9x5_video_CFG_GOOD); heocher = 0; } debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher); dmadesc[0] = buffer + priv->y_offset; dmadesc[1] = REG_HEOxCTRL_DFETCH; dmadesc[2] = buffer + offset_dmadesc; if (priv->u_planeno >= 0) { dmadesc[3] = vb2_dma_contig_plane_paddr(vb, priv->u_planeno) + priv->u_offset; dmadesc[4] = REG_HEOxCTRL_DFETCH; dmadesc[5] = buffer + offset_dmadesc + 3 * 4; } if (priv->v_planeno >= 0) { dmadesc[6] = vb2_dma_contig_plane_paddr(vb, priv->v_planeno) + priv->v_offset; dmadesc[7] = REG_HEOxCTRL_DFETCH; dmadesc[8] = buffer + offset_dmadesc + 6 * 4; } debug("HEOCHSR = %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR)); if (likely(priv->hwstate == at91sam9x5_video_HW_RUNNING)) { at91sam9x5_video_write32(priv, REG_HEOHEAD, dmadesc[2]); if (priv->u_planeno >= 0) at91sam9x5_video_write32(priv, REG_HEOUHEAD, dmadesc[5]); if (priv->v_planeno >= 0) at91sam9x5_video_write32(priv, REG_HEOVHEAD, dmadesc[8]); at91sam9x5_video_write32(priv, REG_HEOCHER, heocher | REG_HEOCHER_A2QEN); } else { at91sam9x5_video_write32(priv, REG_HEOADDR, dmadesc[0]); at91sam9x5_video_write32(priv, REG_HEOCTRL, dmadesc[1]); at91sam9x5_video_write32(priv, REG_HEONEXT, dmadesc[2]); if (priv->u_planeno >= 0) { at91sam9x5_video_write32(priv, REG_HEOUADDR, dmadesc[3]); at91sam9x5_video_write32(priv, REG_HEOUCTRL, dmadesc[4]); at91sam9x5_video_write32(priv, REG_HEOUNEXT, dmadesc[5]); } if (priv->v_planeno >= 0) { at91sam9x5_video_write32(priv, REG_HEOVADDR, dmadesc[6]); at91sam9x5_video_write32(priv, REG_HEOVCTRL, dmadesc[7]); at91sam9x5_video_write32(priv, REG_HEOVNEXT, dmadesc[8]); } at91sam9x5_video_write32(priv, REG_HEOCHER, heocher | REG_HEOCHER_CHEN); priv->hwstate = at91sam9x5_video_HW_RUNNING; } if (priv->cur.vb && at91sam9x5_video_buf_in_use(priv, &priv->cur)) { if (priv->next.vb) { /* drop next; XXX: is this an error? */ debug("drop %p\n", priv->next.vb); vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_ERROR); } } else { if (priv->cur.vb) vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE); priv->cur = priv->next; } priv->next.vb = vb; priv->next.u_planeno = priv->u_planeno; priv->next.v_planeno = priv->v_planeno; priv->next.plane_size[0] = priv->plane_size[0]; priv->next.plane_size[1] = priv->plane_size[1]; priv->next.plane_size[2] = priv->plane_size[2]; }
static void mx3_videobuf_queue(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = to_mx3_vb(vb); struct dma_async_tx_descriptor *txd = buf->txd; struct idmac_channel *ichan = to_idmac_chan(txd->chan); struct idmac_video_param *video = &ichan->params.video; dma_cookie_t cookie; u32 fourcc = icd->current_fmt->host_fmt->fourcc; unsigned long flags; /* This is the configuration of one sg-element */ video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { /* * If the IPU DMA channel is configured to transport * generic 8-bit data, we have to set up correctly the * geometry parameters upon the current pixel format. * So, since the DMA horizontal parameters are expressed * in bytes not pixels, convert these in the right unit. */ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); BUG_ON(bytes_per_line <= 0); video->out_width = bytes_per_line; video->out_height = icd->user_height; video->out_stride = bytes_per_line; } else { /* * For IPU known formats the pixel unit will be managed * successfully by the IPU code */ video->out_width = icd->user_width; video->out_height = icd->user_height; video->out_stride = icd->user_width; } #ifdef DEBUG /* helps to see what DMA actually has written */ if (vb2_plane_vaddr(vb, 0)) memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); #endif spin_lock_irqsave(&mx3_cam->lock, flags); list_add_tail(&buf->queue, &mx3_cam->capture); if (!mx3_cam->active) mx3_cam->active = buf; spin_unlock_irq(&mx3_cam->lock); cookie = txd->tx_submit(txd); dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg)); if (cookie >= 0) return; spin_lock_irq(&mx3_cam->lock); /* Submit error */ list_del_init(&buf->queue); if (mx3_cam->active == buf) mx3_cam->active = NULL; spin_unlock_irqrestore(&mx3_cam->lock, flags); vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); }
int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx, const unsigned char *src, int len, enum dmx_buffer_flags *buffer_flags) { unsigned long flags = 0; void *vbuf = NULL; int todo = len; unsigned char *psrc = (unsigned char *)src; int ll = 0; /* * normal case: This func is called twice from demux driver * one with valid src pointer, second time with NULL pointer */ if (!src || !len) return 0; spin_lock_irqsave(&ctx->slock, flags); if (buffer_flags && *buffer_flags) { ctx->flags |= *buffer_flags; *buffer_flags = 0; } while (todo) { if (!ctx->buf) { if (list_empty(&ctx->dvb_q)) { dprintk(3, "[%s] Buffer overflow!!!\n", ctx->name); break; } ctx->buf = list_entry(ctx->dvb_q.next, struct dvb_buffer, list); ctx->remain = vb2_plane_size(&ctx->buf->vb, 0); ctx->offset = 0; } if (!dvb_vb2_is_streaming(ctx)) { vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_ERROR); list_del(&ctx->buf->list); ctx->buf = NULL; break; } /* Fill buffer */ ll = min(todo, ctx->remain); vbuf = vb2_plane_vaddr(&ctx->buf->vb, 0); memcpy(vbuf + ctx->offset, psrc, ll); todo -= ll; psrc += ll; ctx->remain -= ll; ctx->offset += ll; if (ctx->remain == 0) { vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE); list_del(&ctx->buf->list); ctx->buf = NULL; } } if (ctx->nonblocking && ctx->buf) { vb2_set_plane_payload(&ctx->buf->vb, 0, ll); vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE); list_del(&ctx->buf->list); ctx->buf = NULL; } spin_unlock_irqrestore(&ctx->slock, flags); if (todo) dprintk(1, "[%s] %d bytes are dropped.\n", ctx->name, todo); else dprintk(3, "[%s]\n", ctx->name); dprintk(3, "[%s] %d bytes are copied\n", ctx->name, len - todo); return (len - todo); }
static irqreturn_t unicam_camera_isr(int irq, void *arg) { struct unicam_camera_dev *unicam_dev = (struct unicam_camera_dev *)arg; #if 1 struct v4l2_subdev *sd = soc_camera_to_subdev(unicam_dev->icd); #endif int ret; struct int_desc idesc; struct rx_stat_list rx; u32 isr_status, raw_stat; static unsigned int t1 = 0, t2 = 0, fps = 0; struct buffer_desc im0; dma_addr_t dma_addr; unsigned long flags; /* has the interrupt occured for Channel 0? */ memset(&rx, 0x00, sizeof(struct rx_stat_list)); raw_stat = mm_csi0_get_rx_stat(&rx, 1); if (atomic_read(&unicam_dev->streaming) == 0) { memset(&idesc, 0x00, sizeof(struct int_desc)); isr_status = mm_csi0_get_int_stat(&idesc, 1); pr_err("ISR triggered after stop stat=0x%x istat=0x%x\n", raw_stat, isr_status); goto out; } else if (rx.is) { memset(&idesc, 0x00, sizeof(struct int_desc)); isr_status = mm_csi0_get_int_stat(&idesc, 1); if (idesc.fsi) { if (rx.ps) pr_info("Panic at frame start\n"); } if (idesc.fei || idesc.lci){ struct vb2_buffer *vb = unicam_dev->active; /* FS and FE handling */ if (rx.ps) pr_info("Panic at frame or lineend\n"); fps++; if (t1 == 0 && t2 == 0) t1 = t2 = jiffies_to_msecs(jiffies); t2 = jiffies_to_msecs(jiffies); if (t2 - t1 > 1000) { pr_info(" sensor fps = %d panic count %d\n", fps, unicam_dev->panic_count); fps = 0; t1 = t2; } atomic_set(&unicam_dev->cam_triggered, 0); /*atomic_set(&unicam_dev->retry_count, 0); del_timer(&(unicam_dev->unicam_timer));*/ pr_debug("frame received"); if (!vb) { pr_err("%s: vb is not active\n",__func__); goto out; } if (unicam_dev->skip_frames <= 0) { struct v4l2_control ctrl; int ret = -1; ctrl.value = 0; ctrl.id = V4L2_CID_CAMERA_READ_MODE_CHANGE_REG; ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl); if ((ret >= 0) && (ctrl.value > 0)) { /* capture mode is not ready yet */ unicam_dev->skip_frames = ctrl.value; pr_info("%s: sensor mode change in process ,need_skip_frame=%d\n", __func__, ctrl.value); } } if (likely(unicam_dev->skip_frames <= 0)) { spin_lock_irqsave(&unicam_dev->lock, flags); list_del_init(&to_unicam_camera_vb(vb)->queue); spin_unlock_irqrestore(&unicam_dev->lock, flags); do_gettimeofday(&vb->v4l2_buf.timestamp); vb->v4l2_planes[0].bytesused = 0; if (unicam_dev->icd->current_fmt->code == V4L2_MBUS_FMT_JPEG_1X8) { } else { ret = 1; } vb2_buffer_done(vb, VB2_BUF_STATE_DONE); spin_lock_irqsave(&unicam_dev->lock, flags); if (atomic_read(&unicam_dev->stopping) == 1) { up(&unicam_dev->stop_sem); unicam_dev->active = NULL; } else if (!list_empty(&unicam_dev->capture)) { unicam_dev->active = &list_entry(unicam_dev-> capture.next, struct unicam_camera_buffer, queue)->vb; } else {
/* * omap4iss_video_buffer_next - Complete the current buffer and return the next * @video: ISS video object * * Remove the current video buffer from the DMA queue and fill its timestamp, * field count and state fields before waking up its completion handler. * * For capture video nodes, the buffer state is set to VB2_BUF_STATE_DONE if no * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise. * * The DMA queue is expected to contain at least one buffer. * * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is * empty. */ struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video) { struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); enum iss_pipeline_state state; struct iss_buffer *buf; unsigned long flags; struct timespec ts; spin_lock_irqsave(&video->qlock, flags); if (WARN_ON(list_empty(&video->dmaqueue))) { spin_unlock_irqrestore(&video->qlock, flags); return NULL; } buf = list_first_entry(&video->dmaqueue, struct iss_buffer, list); list_del(&buf->list); spin_unlock_irqrestore(&video->qlock, flags); ktime_get_ts(&ts); buf->vb.v4l2_buf.timestamp.tv_sec = ts.tv_sec; buf->vb.v4l2_buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; /* Do frame number propagation only if this is the output video node. * Frame number either comes from the CSI receivers or it gets * incremented here if H3A is not active. * Note: There is no guarantee that the output buffer will finish * first, so the input number might lag behind by 1 in some cases. */ if (video == pipe->output && !pipe->do_propagation) buf->vb.v4l2_buf.sequence = atomic_inc_return(&pipe->frame_number); else buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number); vb2_buffer_done(&buf->vb, pipe->error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); pipe->error = false; spin_lock_irqsave(&video->qlock, flags); if (list_empty(&video->dmaqueue)) { spin_unlock_irqrestore(&video->qlock, flags); if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISS_PIPELINE_QUEUE_OUTPUT | ISS_PIPELINE_STREAM; else state = ISS_PIPELINE_QUEUE_INPUT | ISS_PIPELINE_STREAM; spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~state; if (video->pipe.stream_state == ISS_PIPELINE_STREAM_CONTINUOUS) video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN; spin_unlock_irqrestore(&pipe->lock, flags); return NULL; } if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { spin_lock(&pipe->lock); pipe->state &= ~ISS_PIPELINE_STREAM; spin_unlock(&pipe->lock); } buf = list_first_entry(&video->dmaqueue, struct iss_buffer, list); spin_unlock_irqrestore(&video->qlock, flags); buf->vb.state = VB2_BUF_STATE_ACTIVE; return buf; }
static irqreturn_t flite_irq_handler(int irq, void *priv) { struct fimc_lite *fimc = priv; struct flite_buffer *vbuf; unsigned long flags; struct timeval *tv; struct timespec ts; u32 intsrc; spin_lock_irqsave(&fimc->slock, flags); intsrc = flite_hw_get_interrupt_source(fimc); flite_hw_clear_pending_irq(fimc); if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) { wake_up(&fimc->irq_queue); goto done; } if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) { clear_bit(ST_FLITE_RUN, &fimc->state); fimc->events.data_overflow++; } if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) { flite_hw_clear_last_capture_end(fimc); clear_bit(ST_FLITE_STREAM, &fimc->state); wake_up(&fimc->irq_queue); } if (fimc->out_path != FIMC_IO_DMA) goto done; if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && test_bit(ST_FLITE_RUN, &fimc->state) && !list_empty(&fimc->active_buf_q) && !list_empty(&fimc->pending_buf_q)) { vbuf = fimc_lite_active_queue_pop(fimc); ktime_get_ts(&ts); tv = &vbuf->vb.v4l2_buf.timestamp; tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; vbuf->vb.v4l2_buf.sequence = fimc->frame_count++; vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE); vbuf = fimc_lite_pending_queue_pop(fimc); flite_hw_set_output_addr(fimc, vbuf->paddr); fimc_lite_active_queue_add(fimc, vbuf); } if (test_bit(ST_FLITE_CONFIG, &fimc->state)) fimc_lite_config_update(fimc); if (list_empty(&fimc->pending_buf_q)) { flite_hw_capture_stop(fimc); clear_bit(ST_FLITE_STREAM, &fimc->state); } done: set_bit(ST_FLITE_RUN, &fimc->state); spin_unlock_irqrestore(&fimc->slock, flags); return IRQ_HANDLED; }
static void cobalt_dma_stream_queue_handler(struct cobalt_stream *s) { struct cobalt *cobalt = s->cobalt; int rx = s->video_channel; struct m00473_freewheel_regmap __iomem *fw = COBALT_CVI_FREEWHEEL(s->cobalt, rx); struct m00233_video_measure_regmap __iomem *vmr = COBALT_CVI_VMR(s->cobalt, rx); struct m00389_cvi_regmap __iomem *cvi = COBALT_CVI(s->cobalt, rx); struct m00479_clk_loss_detector_regmap __iomem *clkloss = COBALT_CVI_CLK_LOSS(s->cobalt, rx); struct cobalt_buffer *cb; bool skip = false; spin_lock(&s->irqlock); if (list_empty(&s->bufs)) { pr_err("no buffers!\n"); spin_unlock(&s->irqlock); return; } /* Give the fresh filled up buffer to the user. * Note that the interrupt is only sent if the DMA can continue * with a new buffer, so it is always safe to return this buffer * to userspace. */ cb = list_first_entry(&s->bufs, struct cobalt_buffer, list); list_del(&cb->list); spin_unlock(&s->irqlock); if (s->is_audio || s->is_output) goto done; if (s->unstable_frame) { uint32_t stat = ioread32(&vmr->irq_status); iowrite32(stat, &vmr->irq_status); if (!(ioread32(&vmr->status) & M00233_STATUS_BITMAP_INIT_DONE_MSK)) { cobalt_dbg(1, "!init_done\n"); if (s->enable_freewheel) goto restart_fw; goto done; } if (ioread32(&clkloss->status) & M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) { iowrite32(0, &clkloss->ctrl); iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl); cobalt_dbg(1, "no clock\n"); if (s->enable_freewheel) goto restart_fw; goto done; } if ((stat & (M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK | M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK)) || ioread32(&vmr->vactive_area) != s->timings.bt.height || ioread32(&vmr->hactive_area) != s->timings.bt.width) { cobalt_dbg(1, "unstable\n"); if (s->enable_freewheel) goto restart_fw; goto done; } if (!s->enable_cvi) { s->enable_cvi = true; iowrite32(M00389_CONTROL_BITMAP_ENABLE_MSK, &cvi->control); goto done; } if (!(ioread32(&cvi->status) & M00389_STATUS_BITMAP_LOCK_MSK)) { cobalt_dbg(1, "cvi no lock\n"); if (s->enable_freewheel) goto restart_fw; goto done; } if (!s->enable_freewheel) { cobalt_dbg(1, "stable\n"); s->enable_freewheel = true; iowrite32(0, &fw->ctrl); goto done; } cobalt_dbg(1, "enabled fw\n"); iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK | M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK, &vmr->control); iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK, &fw->ctrl); s->enable_freewheel = false; s->unstable_frame = false; s->skip_first_frames = 2; skip = true; goto done; } if (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) { restart_fw: cobalt_dbg(1, "lost lock\n"); iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK | M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, &fw->ctrl); iowrite32(0, &cvi->control); s->unstable_frame = true; s->enable_freewheel = false; s->enable_cvi = false; } done: if (s->skip_first_frames) { skip = true; s->skip_first_frames--; } cb->vb.vb2_buf.timestamp = ktime_get_ns(); /* TODO: the sequence number should be read from the FPGA so we also know about dropped frames. */ cb->vb.sequence = s->sequence++; vb2_buffer_done(&cb->vb.vb2_buf, (skip || s->unstable_frame) ? VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE); }