static int solo_v4l2_ch_ext_16up(struct solo6010_dev *solo_dev, int on) { int sy, ysize, hsize, i; if (!on) { for (i = 0; i < 16; i++) solo_win_setup(solo_dev, i, solo_dev->video_hsize, solo_vlines(solo_dev), solo_dev->video_hsize, solo_vlines(solo_dev), 0); return 0; } ysize = solo_vlines(solo_dev) / 4; hsize = solo_dev->video_hsize / 4; for (sy = 0, i = 0; i < 4; i++, sy += ysize) { solo_win_setup(solo_dev, i * 4, 0, sy, hsize, sy + ysize, 5); solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy, hsize * 2, sy + ysize, 5); solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy, hsize * 3, sy + ysize, 5); solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy, solo_dev->video_hsize, sy + ysize, 5); } return 0; }
static int solo_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct solo_filehandle *fh = priv; struct solo6010_dev *solo_dev = fh->solo_dev; struct v4l2_pix_format *pix = &f->fmt.pix; int image_size = solo_image_size(solo_dev); /* Check supported sizes */ if (pix->width != solo_dev->video_hsize) pix->width = solo_dev->video_hsize; if (pix->height != solo_vlines(solo_dev)) pix->height = solo_vlines(solo_dev); if (pix->sizeimage != image_size) pix->sizeimage = image_size; /* Check formats */ if (pix->field == V4L2_FIELD_ANY) pix->field = SOLO_DISP_PIX_FIELD; if (pix->pixelformat != V4L2_PIX_FMT_UYVY || pix->field != SOLO_DISP_PIX_FIELD || pix->colorspace != V4L2_COLORSPACE_SMPTE170M) return -EINVAL; return 0; }
static int solo_v4l2_ch_ext_4up(struct solo6010_dev *solo_dev, u8 idx, int on) { u8 ch = idx * 4; if (ch >= solo_dev->nr_chans) return -EINVAL; if (!on) { u8 i; for (i = ch; i < ch + 4; i++) solo_win_setup(solo_dev, i, solo_dev->video_hsize, solo_vlines(solo_dev), solo_dev->video_hsize, solo_vlines(solo_dev), 0); return 0; } /* Row 1 */ solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2, solo_vlines(solo_dev) / 2, 3); solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0, solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3); /* Row 2 */ solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2, solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3); solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2, solo_vlines(solo_dev) / 2, solo_dev->video_hsize, solo_vlines(solo_dev), 3); return 0; }
static int solo_buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { struct solo_filehandle *fh = vq->priv_data; struct solo6010_dev *solo_dev = fh->solo_dev; vb->size = solo_image_size(solo_dev); if (vb->baddr != 0 && vb->bsize < vb->size) return -EINVAL; /* XXX: These properties only change when queue is idle */ vb->width = solo_dev->video_hsize; vb->height = solo_vlines(solo_dev); vb->bytesperline = solo_bytesperline(solo_dev); vb->field = field; if (vb->state == VIDEOBUF_NEEDS_INIT) { int rc = videobuf_iolock(vq, vb, NULL); if (rc < 0) { videobuf_dma_contig_free(vq, vb); vb->state = VIDEOBUF_NEEDS_INIT; return rc; } } vb->state = VIDEOBUF_PREPARED; return 0; }
static void solo_fillbuf(struct solo_dev *solo_dev, struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); dma_addr_t addr; unsigned int fdma_addr; int error = -1; int i; addr = vb2_dma_contig_plane_dma_addr(vb, 0); if (!addr) goto finish_buf; if (erase_off(solo_dev)) { void *p = vb2_plane_vaddr(vb, 0); int image_size = solo_image_size(solo_dev); for (i = 0; i < image_size; i += 2) { ((u8 *)p)[i] = 0x80; ((u8 *)p)[i + 1] = 0x00; } error = 0; } else { fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write * (SOLO_HW_BPL * solo_vlines(solo_dev))); error = solo_p2m_dma_t(solo_dev, 0, addr, fdma_addr, solo_bytesperline(solo_dev), solo_vlines(solo_dev), SOLO_HW_BPL); } finish_buf: if (!error) { vb2_set_plane_payload(vb, 0, solo_vlines(solo_dev) * solo_bytesperline(solo_dev)); vbuf->sequence = solo_dev->sequence++; vb->timestamp = ktime_get_ns(); } vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); }
static void solo_fillbuf(struct solo_filehandle *fh, struct videobuf_buffer *vb) { struct solo6010_dev *solo_dev = fh->solo_dev; dma_addr_t vbuf; unsigned int fdma_addr; int frame_size; int error = 1; int i; if (!(vbuf = videobuf_to_dma_contig(vb))) goto finish_buf; if (erase_off(solo_dev)) { void *p = videobuf_queue_to_vaddr(&fh->vidq, vb); int image_size = solo_image_size(solo_dev); for (i = 0; i < image_size; i += 2) { ((u8 *)p)[i] = 0x80; ((u8 *)p)[i + 1] = 0x00; } error = 0; goto finish_buf; } frame_size = SOLO_HW_BPL * solo_vlines(solo_dev); fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write * frame_size); for (i = 0; i < frame_size / SOLO_DISP_BUF_SIZE; i++) { int j; for (j = 0; j < (SOLO_DISP_BUF_SIZE / SOLO_HW_BPL); j++) { if (solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_DISP, 0, vbuf, fdma_addr + (j * SOLO_HW_BPL), solo_bytesperline(solo_dev))) goto finish_buf; vbuf += solo_bytesperline(solo_dev); } fdma_addr += SOLO_DISP_BUF_SIZE; } error = 0; finish_buf: if (error) { vb->state = VIDEOBUF_ERROR; } else { vb->state = VIDEOBUF_DONE; vb->field_count++; do_gettimeofday(&vb->ts); } wake_up(&vb->done); return; }
static void solo_fillbuf(struct solo_filehandle *fh, struct videobuf_buffer *vb) { struct solo_dev *solo_dev = fh->solo_dev; dma_addr_t vbuf; unsigned int fdma_addr; int error = -1; int i; vbuf = videobuf_to_dma_contig(vb); if (!vbuf) goto finish_buf; if (erase_off(solo_dev)) { void *p = videobuf_queue_to_vaddr(&fh->vidq, vb); int image_size = solo_image_size(solo_dev); for (i = 0; i < image_size; i += 2) { ((u8 *)p)[i] = 0x80; ((u8 *)p)[i + 1] = 0x00; } error = 0; } else { fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write * (SOLO_HW_BPL * solo_vlines(solo_dev))); error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr, solo_bytesperline(solo_dev), solo_vlines(solo_dev), SOLO_HW_BPL); } finish_buf: if (error) { vb->state = VIDEOBUF_ERROR; } else { vb->state = VIDEOBUF_DONE; vb->field_count++; } wake_up(&vb->done); }
static int solo_v4l2_ch(struct solo6010_dev *solo_dev, u8 ch, int on) { u8 ext_ch; if (ch < solo_dev->nr_chans) { solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize, on ? 0 : solo_vlines(solo_dev), solo_dev->video_hsize, solo_vlines(solo_dev), on ? 1 : 0); return 0; } if (ch >= solo_dev->nr_chans + solo_dev->nr_ext) return -EINVAL; ext_ch = ch - solo_dev->nr_chans; /* 4up's first */ if (ext_ch < 4) return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on); /* Remaining case is 16up for 16-port */ return solo_v4l2_ch_ext_16up(solo_dev, on); }
static int solo_get_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct solo_filehandle *fh = priv; struct solo6010_dev *solo_dev = fh->solo_dev; struct v4l2_pix_format *pix = &f->fmt.pix; pix->width = solo_dev->video_hsize; pix->height = solo_vlines(solo_dev); pix->pixelformat = V4L2_PIX_FMT_UYVY; pix->field = SOLO_DISP_PIX_FIELD; pix->sizeimage = solo_image_size(solo_dev); pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->bytesperline = solo_bytesperline(solo_dev); return 0; }
static int solo_get_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct solo_dev *solo_dev = video_drvdata(file); struct v4l2_pix_format *pix = &f->fmt.pix; pix->width = solo_dev->video_hsize; pix->height = solo_vlines(solo_dev); pix->pixelformat = V4L2_PIX_FMT_UYVY; pix->field = V4L2_FIELD_INTERLACED; pix->sizeimage = solo_image_size(solo_dev); pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->bytesperline = solo_bytesperline(solo_dev); pix->priv = 0; return 0; }