1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2b285192aSMauro Carvalho Chehab /* 3b285192aSMauro Carvalho Chehab * cx18 init/start/stop/exit stream functions 4b285192aSMauro Carvalho Chehab * 5b285192aSMauro Carvalho Chehab * Derived from ivtv-streams.c 6b285192aSMauro Carvalho Chehab * 7b285192aSMauro Carvalho Chehab * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 8b285192aSMauro Carvalho Chehab * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> 9b285192aSMauro Carvalho Chehab */ 10b285192aSMauro Carvalho Chehab 11b285192aSMauro Carvalho Chehab #include "cx18-driver.h" 12b285192aSMauro Carvalho Chehab #include "cx18-io.h" 13b285192aSMauro Carvalho Chehab #include "cx18-fileops.h" 14b285192aSMauro Carvalho Chehab #include "cx18-mailbox.h" 15b285192aSMauro Carvalho Chehab #include "cx18-i2c.h" 16b285192aSMauro Carvalho Chehab #include "cx18-queue.h" 17b285192aSMauro Carvalho Chehab #include "cx18-ioctl.h" 18b285192aSMauro Carvalho Chehab #include "cx18-streams.h" 19b285192aSMauro Carvalho Chehab #include "cx18-cards.h" 20b285192aSMauro Carvalho Chehab #include "cx18-scb.h" 21b285192aSMauro Carvalho Chehab #include "cx18-dvb.h" 22b285192aSMauro Carvalho Chehab 23b285192aSMauro Carvalho Chehab #define CX18_DSP0_INTERRUPT_MASK 0xd0004C 24b285192aSMauro Carvalho Chehab 25e66fb184SBhumika Goyal static const struct v4l2_file_operations cx18_v4l2_enc_fops = { 26b285192aSMauro Carvalho Chehab .owner = THIS_MODULE, 27b285192aSMauro Carvalho Chehab .read = cx18_v4l2_read, 28b285192aSMauro Carvalho Chehab .open = cx18_v4l2_open, 29b285192aSMauro Carvalho Chehab .unlocked_ioctl = video_ioctl2, 30b285192aSMauro Carvalho Chehab .release = cx18_v4l2_close, 31b285192aSMauro Carvalho Chehab .poll = cx18_v4l2_enc_poll, 32b285192aSMauro Carvalho Chehab .mmap = cx18_v4l2_mmap, 33b285192aSMauro Carvalho Chehab }; 34b285192aSMauro Carvalho Chehab 35b285192aSMauro Carvalho Chehab /* offset from 0 to register ts v4l2 minors on */ 36b285192aSMauro Carvalho Chehab #define CX18_V4L2_ENC_TS_OFFSET 16 37b285192aSMauro Carvalho Chehab /* offset from 0 to register pcm v4l2 minors on */ 38b285192aSMauro Carvalho Chehab #define CX18_V4L2_ENC_PCM_OFFSET 24 39b285192aSMauro Carvalho Chehab /* offset from 0 to register yuv v4l2 minors on */ 40b285192aSMauro Carvalho Chehab #define CX18_V4L2_ENC_YUV_OFFSET 32 41b285192aSMauro Carvalho Chehab 42b285192aSMauro Carvalho Chehab static struct { 43b285192aSMauro Carvalho Chehab const char *name; 44b285192aSMauro Carvalho Chehab int vfl_type; 45b285192aSMauro Carvalho Chehab int num_offset; 46b285192aSMauro Carvalho Chehab int dma; 47dfdf780bSHans Verkuil u32 caps; 48b285192aSMauro Carvalho Chehab } cx18_stream_info[] = { 49b285192aSMauro Carvalho Chehab { /* CX18_ENC_STREAM_TYPE_MPG */ 50b285192aSMauro Carvalho Chehab "encoder MPEG", 51*3e30a927SHans Verkuil VFL_TYPE_VIDEO, 0, 52ff82b211SHans Verkuil PCI_DMA_FROMDEVICE, 53dfdf780bSHans Verkuil V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 54dfdf780bSHans Verkuil V4L2_CAP_AUDIO | V4L2_CAP_TUNER 55b285192aSMauro Carvalho Chehab }, 56b285192aSMauro Carvalho Chehab { /* CX18_ENC_STREAM_TYPE_TS */ 57b285192aSMauro Carvalho Chehab "TS", 58*3e30a927SHans Verkuil VFL_TYPE_VIDEO, -1, 59ff82b211SHans Verkuil PCI_DMA_FROMDEVICE, 60b285192aSMauro Carvalho Chehab }, 61b285192aSMauro Carvalho Chehab { /* CX18_ENC_STREAM_TYPE_YUV */ 62b285192aSMauro Carvalho Chehab "encoder YUV", 63*3e30a927SHans Verkuil VFL_TYPE_VIDEO, CX18_V4L2_ENC_YUV_OFFSET, 64ff82b211SHans Verkuil PCI_DMA_FROMDEVICE, 65dfdf780bSHans Verkuil V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 66dfdf780bSHans Verkuil V4L2_CAP_STREAMING | V4L2_CAP_AUDIO | V4L2_CAP_TUNER 67b285192aSMauro Carvalho Chehab }, 68b285192aSMauro Carvalho Chehab { /* CX18_ENC_STREAM_TYPE_VBI */ 69b285192aSMauro Carvalho Chehab "encoder VBI", 70b285192aSMauro Carvalho Chehab VFL_TYPE_VBI, 0, 71ff82b211SHans Verkuil PCI_DMA_FROMDEVICE, 72dfdf780bSHans Verkuil V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | 73dfdf780bSHans Verkuil V4L2_CAP_READWRITE | V4L2_CAP_TUNER 74b285192aSMauro Carvalho Chehab }, 75b285192aSMauro Carvalho Chehab { /* CX18_ENC_STREAM_TYPE_PCM */ 76b285192aSMauro Carvalho Chehab "encoder PCM audio", 77*3e30a927SHans Verkuil VFL_TYPE_VIDEO, CX18_V4L2_ENC_PCM_OFFSET, 78ff82b211SHans Verkuil PCI_DMA_FROMDEVICE, 792b4fd3edSHans Verkuil V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, 80b285192aSMauro Carvalho Chehab }, 81b285192aSMauro Carvalho Chehab { /* CX18_ENC_STREAM_TYPE_IDX */ 82b285192aSMauro Carvalho Chehab "encoder IDX", 83*3e30a927SHans Verkuil VFL_TYPE_VIDEO, -1, 84ff82b211SHans Verkuil PCI_DMA_FROMDEVICE, 85b285192aSMauro Carvalho Chehab }, 86b285192aSMauro Carvalho Chehab { /* CX18_ENC_STREAM_TYPE_RAD */ 87b285192aSMauro Carvalho Chehab "encoder radio", 88b285192aSMauro Carvalho Chehab VFL_TYPE_RADIO, 0, 89ff82b211SHans Verkuil PCI_DMA_NONE, 90dfdf780bSHans Verkuil V4L2_CAP_RADIO | V4L2_CAP_TUNER 91b285192aSMauro Carvalho Chehab }, 92b285192aSMauro Carvalho Chehab }; 93b285192aSMauro Carvalho Chehab 94b285192aSMauro Carvalho Chehab 955e6e81b2SMauro Carvalho Chehab static void cx18_dma_free(struct videobuf_queue *q, 96b285192aSMauro Carvalho Chehab struct cx18_stream *s, struct cx18_videobuf_buffer *buf) 97b285192aSMauro Carvalho Chehab { 98b285192aSMauro Carvalho Chehab videobuf_waiton(q, &buf->vb, 0, 0); 99b285192aSMauro Carvalho Chehab videobuf_vmalloc_free(&buf->vb); 100b285192aSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_NEEDS_INIT; 101b285192aSMauro Carvalho Chehab } 102b285192aSMauro Carvalho Chehab 103b285192aSMauro Carvalho Chehab static int cx18_prepare_buffer(struct videobuf_queue *q, 104b285192aSMauro Carvalho Chehab struct cx18_stream *s, 105b285192aSMauro Carvalho Chehab struct cx18_videobuf_buffer *buf, 106b285192aSMauro Carvalho Chehab u32 pixelformat, 107b285192aSMauro Carvalho Chehab unsigned int width, unsigned int height, 108b285192aSMauro Carvalho Chehab enum v4l2_field field) 109b285192aSMauro Carvalho Chehab { 110b285192aSMauro Carvalho Chehab struct cx18 *cx = s->cx; 111b285192aSMauro Carvalho Chehab int rc = 0; 112b285192aSMauro Carvalho Chehab 113b285192aSMauro Carvalho Chehab /* check settings */ 114b285192aSMauro Carvalho Chehab buf->bytes_used = 0; 115b285192aSMauro Carvalho Chehab 116b285192aSMauro Carvalho Chehab if ((width < 48) || (height < 32)) 117b285192aSMauro Carvalho Chehab return -EINVAL; 118b285192aSMauro Carvalho Chehab 119b285192aSMauro Carvalho Chehab buf->vb.size = (width * height * 2); 120b285192aSMauro Carvalho Chehab if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) 121b285192aSMauro Carvalho Chehab return -EINVAL; 122b285192aSMauro Carvalho Chehab 123b285192aSMauro Carvalho Chehab /* alloc + fill struct (if changed) */ 124b285192aSMauro Carvalho Chehab if (buf->vb.width != width || buf->vb.height != height || 125b285192aSMauro Carvalho Chehab buf->vb.field != field || s->pixelformat != pixelformat || 126b285192aSMauro Carvalho Chehab buf->tvnorm != cx->std) { 127b285192aSMauro Carvalho Chehab 128b285192aSMauro Carvalho Chehab buf->vb.width = width; 129b285192aSMauro Carvalho Chehab buf->vb.height = height; 130b285192aSMauro Carvalho Chehab buf->vb.field = field; 131b285192aSMauro Carvalho Chehab buf->tvnorm = cx->std; 132b285192aSMauro Carvalho Chehab s->pixelformat = pixelformat; 133b285192aSMauro Carvalho Chehab 134b285192aSMauro Carvalho Chehab /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) 135b285192aSMauro Carvalho Chehab UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ 136b285192aSMauro Carvalho Chehab if (s->pixelformat == V4L2_PIX_FMT_HM12) 137b285192aSMauro Carvalho Chehab s->vb_bytes_per_frame = height * 720 * 3 / 2; 138b285192aSMauro Carvalho Chehab else 139b285192aSMauro Carvalho Chehab s->vb_bytes_per_frame = height * 720 * 2; 140b285192aSMauro Carvalho Chehab cx18_dma_free(q, s, buf); 141b285192aSMauro Carvalho Chehab } 142b285192aSMauro Carvalho Chehab 143b285192aSMauro Carvalho Chehab if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) 144b285192aSMauro Carvalho Chehab return -EINVAL; 145b285192aSMauro Carvalho Chehab 146b285192aSMauro Carvalho Chehab if (buf->vb.field == 0) 147b285192aSMauro Carvalho Chehab buf->vb.field = V4L2_FIELD_INTERLACED; 148b285192aSMauro Carvalho Chehab 149b285192aSMauro Carvalho Chehab if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { 150b285192aSMauro Carvalho Chehab buf->vb.width = width; 151b285192aSMauro Carvalho Chehab buf->vb.height = height; 152b285192aSMauro Carvalho Chehab buf->vb.field = field; 153b285192aSMauro Carvalho Chehab buf->tvnorm = cx->std; 154b285192aSMauro Carvalho Chehab s->pixelformat = pixelformat; 155b285192aSMauro Carvalho Chehab 156b285192aSMauro Carvalho Chehab /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) 157b285192aSMauro Carvalho Chehab UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ 158b285192aSMauro Carvalho Chehab if (s->pixelformat == V4L2_PIX_FMT_HM12) 159b285192aSMauro Carvalho Chehab s->vb_bytes_per_frame = height * 720 * 3 / 2; 160b285192aSMauro Carvalho Chehab else 161b285192aSMauro Carvalho Chehab s->vb_bytes_per_frame = height * 720 * 2; 162b285192aSMauro Carvalho Chehab rc = videobuf_iolock(q, &buf->vb, NULL); 163b285192aSMauro Carvalho Chehab if (rc != 0) 164b285192aSMauro Carvalho Chehab goto fail; 165b285192aSMauro Carvalho Chehab } 166b285192aSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_PREPARED; 167b285192aSMauro Carvalho Chehab return 0; 168b285192aSMauro Carvalho Chehab 169b285192aSMauro Carvalho Chehab fail: 170b285192aSMauro Carvalho Chehab cx18_dma_free(q, s, buf); 171b285192aSMauro Carvalho Chehab return rc; 172b285192aSMauro Carvalho Chehab 173b285192aSMauro Carvalho Chehab } 174b285192aSMauro Carvalho Chehab 175b285192aSMauro Carvalho Chehab /* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576) 176b285192aSMauro Carvalho Chehab 1440 is a single line of 4:2:2 YUV at 720 luma samples wide 177b285192aSMauro Carvalho Chehab */ 178b285192aSMauro Carvalho Chehab #define VB_MIN_BUFFERS 32 179b285192aSMauro Carvalho Chehab #define VB_MIN_BUFSIZE 4147200 180b285192aSMauro Carvalho Chehab 181b285192aSMauro Carvalho Chehab static int buffer_setup(struct videobuf_queue *q, 182b285192aSMauro Carvalho Chehab unsigned int *count, unsigned int *size) 183b285192aSMauro Carvalho Chehab { 184b285192aSMauro Carvalho Chehab struct cx18_stream *s = q->priv_data; 185b285192aSMauro Carvalho Chehab struct cx18 *cx = s->cx; 186b285192aSMauro Carvalho Chehab 187b285192aSMauro Carvalho Chehab *size = 2 * cx->cxhdl.width * cx->cxhdl.height; 188b285192aSMauro Carvalho Chehab if (*count == 0) 189b285192aSMauro Carvalho Chehab *count = VB_MIN_BUFFERS; 190b285192aSMauro Carvalho Chehab 191b285192aSMauro Carvalho Chehab while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) 192b285192aSMauro Carvalho Chehab (*count)--; 193b285192aSMauro Carvalho Chehab 194b285192aSMauro Carvalho Chehab q->field = V4L2_FIELD_INTERLACED; 195b285192aSMauro Carvalho Chehab q->last = V4L2_FIELD_INTERLACED; 196b285192aSMauro Carvalho Chehab 197b285192aSMauro Carvalho Chehab return 0; 198b285192aSMauro Carvalho Chehab } 199b285192aSMauro Carvalho Chehab 200b285192aSMauro Carvalho Chehab static int buffer_prepare(struct videobuf_queue *q, 201b285192aSMauro Carvalho Chehab struct videobuf_buffer *vb, 202b285192aSMauro Carvalho Chehab enum v4l2_field field) 203b285192aSMauro Carvalho Chehab { 204b285192aSMauro Carvalho Chehab struct cx18_videobuf_buffer *buf = 205b285192aSMauro Carvalho Chehab container_of(vb, struct cx18_videobuf_buffer, vb); 206b285192aSMauro Carvalho Chehab struct cx18_stream *s = q->priv_data; 207b285192aSMauro Carvalho Chehab struct cx18 *cx = s->cx; 208b285192aSMauro Carvalho Chehab 209b285192aSMauro Carvalho Chehab return cx18_prepare_buffer(q, s, buf, s->pixelformat, 210b285192aSMauro Carvalho Chehab cx->cxhdl.width, cx->cxhdl.height, field); 211b285192aSMauro Carvalho Chehab } 212b285192aSMauro Carvalho Chehab 213b285192aSMauro Carvalho Chehab static void buffer_release(struct videobuf_queue *q, 214b285192aSMauro Carvalho Chehab struct videobuf_buffer *vb) 215b285192aSMauro Carvalho Chehab { 216b285192aSMauro Carvalho Chehab struct cx18_videobuf_buffer *buf = 217b285192aSMauro Carvalho Chehab container_of(vb, struct cx18_videobuf_buffer, vb); 218b285192aSMauro Carvalho Chehab struct cx18_stream *s = q->priv_data; 219b285192aSMauro Carvalho Chehab 220b285192aSMauro Carvalho Chehab cx18_dma_free(q, s, buf); 221b285192aSMauro Carvalho Chehab } 222b285192aSMauro Carvalho Chehab 223b285192aSMauro Carvalho Chehab static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) 224b285192aSMauro Carvalho Chehab { 225b285192aSMauro Carvalho Chehab struct cx18_videobuf_buffer *buf = 226b285192aSMauro Carvalho Chehab container_of(vb, struct cx18_videobuf_buffer, vb); 227b285192aSMauro Carvalho Chehab struct cx18_stream *s = q->priv_data; 228b285192aSMauro Carvalho Chehab 229b285192aSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_QUEUED; 230b285192aSMauro Carvalho Chehab 231b285192aSMauro Carvalho Chehab list_add_tail(&buf->vb.queue, &s->vb_capture); 232b285192aSMauro Carvalho Chehab } 233b285192aSMauro Carvalho Chehab 23466883248SJulia Lawall static const struct videobuf_queue_ops cx18_videobuf_qops = { 235b285192aSMauro Carvalho Chehab .buf_setup = buffer_setup, 236b285192aSMauro Carvalho Chehab .buf_prepare = buffer_prepare, 237b285192aSMauro Carvalho Chehab .buf_queue = buffer_queue, 238b285192aSMauro Carvalho Chehab .buf_release = buffer_release, 239b285192aSMauro Carvalho Chehab }; 240b285192aSMauro Carvalho Chehab 241b285192aSMauro Carvalho Chehab static void cx18_stream_init(struct cx18 *cx, int type) 242b285192aSMauro Carvalho Chehab { 243b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[type]; 244b285192aSMauro Carvalho Chehab 245b285192aSMauro Carvalho Chehab memset(s, 0, sizeof(*s)); 246b285192aSMauro Carvalho Chehab 247b285192aSMauro Carvalho Chehab /* initialize cx18_stream fields */ 248b285192aSMauro Carvalho Chehab s->dvb = NULL; 249b285192aSMauro Carvalho Chehab s->cx = cx; 250b285192aSMauro Carvalho Chehab s->type = type; 251b285192aSMauro Carvalho Chehab s->name = cx18_stream_info[type].name; 252b285192aSMauro Carvalho Chehab s->handle = CX18_INVALID_TASK_HANDLE; 253b285192aSMauro Carvalho Chehab 254b285192aSMauro Carvalho Chehab s->dma = cx18_stream_info[type].dma; 255dfdf780bSHans Verkuil s->v4l2_dev_caps = cx18_stream_info[type].caps; 256b285192aSMauro Carvalho Chehab s->buffers = cx->stream_buffers[type]; 257b285192aSMauro Carvalho Chehab s->buf_size = cx->stream_buf_size[type]; 258b285192aSMauro Carvalho Chehab INIT_LIST_HEAD(&s->buf_pool); 259b285192aSMauro Carvalho Chehab s->bufs_per_mdl = 1; 260b285192aSMauro Carvalho Chehab s->mdl_size = s->buf_size * s->bufs_per_mdl; 261b285192aSMauro Carvalho Chehab 262b285192aSMauro Carvalho Chehab init_waitqueue_head(&s->waitq); 263b285192aSMauro Carvalho Chehab s->id = -1; 264b285192aSMauro Carvalho Chehab spin_lock_init(&s->q_free.lock); 265b285192aSMauro Carvalho Chehab cx18_queue_init(&s->q_free); 266b285192aSMauro Carvalho Chehab spin_lock_init(&s->q_busy.lock); 267b285192aSMauro Carvalho Chehab cx18_queue_init(&s->q_busy); 268b285192aSMauro Carvalho Chehab spin_lock_init(&s->q_full.lock); 269b285192aSMauro Carvalho Chehab cx18_queue_init(&s->q_full); 270b285192aSMauro Carvalho Chehab spin_lock_init(&s->q_idle.lock); 271b285192aSMauro Carvalho Chehab cx18_queue_init(&s->q_idle); 272b285192aSMauro Carvalho Chehab 273b285192aSMauro Carvalho Chehab INIT_WORK(&s->out_work_order, cx18_out_work_handler); 274b285192aSMauro Carvalho Chehab 275b285192aSMauro Carvalho Chehab INIT_LIST_HEAD(&s->vb_capture); 276162e6376SKees Cook timer_setup(&s->vb_timeout, cx18_vb_timeout, 0); 277b285192aSMauro Carvalho Chehab spin_lock_init(&s->vb_lock); 278b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_YUV) { 279b285192aSMauro Carvalho Chehab spin_lock_init(&s->vbuf_q_lock); 280b285192aSMauro Carvalho Chehab 281b285192aSMauro Carvalho Chehab s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 282b285192aSMauro Carvalho Chehab videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops, 283b285192aSMauro Carvalho Chehab &cx->pci_dev->dev, &s->vbuf_q_lock, 284b285192aSMauro Carvalho Chehab V4L2_BUF_TYPE_VIDEO_CAPTURE, 285b285192aSMauro Carvalho Chehab V4L2_FIELD_INTERLACED, 286b285192aSMauro Carvalho Chehab sizeof(struct cx18_videobuf_buffer), 287b285192aSMauro Carvalho Chehab s, &cx->serialize_lock); 288b285192aSMauro Carvalho Chehab 289b285192aSMauro Carvalho Chehab /* Assume the previous pixel default */ 290b285192aSMauro Carvalho Chehab s->pixelformat = V4L2_PIX_FMT_HM12; 291b285192aSMauro Carvalho Chehab s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; 2923a29a4f1SHans Verkuil s->vb_bytes_per_line = 720; 293b285192aSMauro Carvalho Chehab } 294b285192aSMauro Carvalho Chehab } 295b285192aSMauro Carvalho Chehab 296b285192aSMauro Carvalho Chehab static int cx18_prep_dev(struct cx18 *cx, int type) 297b285192aSMauro Carvalho Chehab { 298b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[type]; 299b285192aSMauro Carvalho Chehab u32 cap = cx->v4l2_cap; 300b285192aSMauro Carvalho Chehab int num_offset = cx18_stream_info[type].num_offset; 301b285192aSMauro Carvalho Chehab int num = cx->instance + cx18_first_minor + num_offset; 302b285192aSMauro Carvalho Chehab 303b285192aSMauro Carvalho Chehab /* 304b285192aSMauro Carvalho Chehab * These five fields are always initialized. 30508569d64SHans Verkuil * For analog capture related streams, if video_dev.v4l2_dev == NULL then the 306b285192aSMauro Carvalho Chehab * stream is not in use. 307b285192aSMauro Carvalho Chehab * For the TS stream, if dvb == NULL then the stream is not in use. 308b285192aSMauro Carvalho Chehab * In those cases no other fields but these four can be used. 309b285192aSMauro Carvalho Chehab */ 31008569d64SHans Verkuil s->video_dev.v4l2_dev = NULL; 311b285192aSMauro Carvalho Chehab s->dvb = NULL; 312b285192aSMauro Carvalho Chehab s->cx = cx; 313b285192aSMauro Carvalho Chehab s->type = type; 314b285192aSMauro Carvalho Chehab s->name = cx18_stream_info[type].name; 315b285192aSMauro Carvalho Chehab 316b285192aSMauro Carvalho Chehab /* Check whether the radio is supported */ 317b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) 318b285192aSMauro Carvalho Chehab return 0; 319b285192aSMauro Carvalho Chehab 320b285192aSMauro Carvalho Chehab /* Check whether VBI is supported */ 321b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_VBI && 322b285192aSMauro Carvalho Chehab !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) 323b285192aSMauro Carvalho Chehab return 0; 324b285192aSMauro Carvalho Chehab 325b285192aSMauro Carvalho Chehab /* User explicitly selected 0 buffers for these streams, so don't 326b285192aSMauro Carvalho Chehab create them. */ 327b285192aSMauro Carvalho Chehab if (cx18_stream_info[type].dma != PCI_DMA_NONE && 328b285192aSMauro Carvalho Chehab cx->stream_buffers[type] == 0) { 329b285192aSMauro Carvalho Chehab CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); 330b285192aSMauro Carvalho Chehab return 0; 331b285192aSMauro Carvalho Chehab } 332b285192aSMauro Carvalho Chehab 333b285192aSMauro Carvalho Chehab cx18_stream_init(cx, type); 334b285192aSMauro Carvalho Chehab 335b285192aSMauro Carvalho Chehab /* Allocate the cx18_dvb struct only for the TS on cards with DTV */ 336b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_TS) { 337b285192aSMauro Carvalho Chehab if (cx->card->hw_all & CX18_HW_DVB) { 338b285192aSMauro Carvalho Chehab s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL); 339b285192aSMauro Carvalho Chehab if (s->dvb == NULL) { 3406beb1388SMauro Carvalho Chehab CX18_ERR("Couldn't allocate cx18_dvb structure for %s\n", 3416beb1388SMauro Carvalho Chehab s->name); 342b285192aSMauro Carvalho Chehab return -ENOMEM; 343b285192aSMauro Carvalho Chehab } 344b285192aSMauro Carvalho Chehab } else { 345b285192aSMauro Carvalho Chehab /* Don't need buffers for the TS, if there is no DVB */ 346b285192aSMauro Carvalho Chehab s->buffers = 0; 347b285192aSMauro Carvalho Chehab } 348b285192aSMauro Carvalho Chehab } 349b285192aSMauro Carvalho Chehab 350b285192aSMauro Carvalho Chehab if (num_offset == -1) 351b285192aSMauro Carvalho Chehab return 0; 352b285192aSMauro Carvalho Chehab 35308569d64SHans Verkuil /* initialize the v4l2 video device structure */ 35408569d64SHans Verkuil snprintf(s->video_dev.name, sizeof(s->video_dev.name), "%s %s", 355b285192aSMauro Carvalho Chehab cx->v4l2_dev.name, s->name); 356b285192aSMauro Carvalho Chehab 35708569d64SHans Verkuil s->video_dev.num = num; 35808569d64SHans Verkuil s->video_dev.v4l2_dev = &cx->v4l2_dev; 35908569d64SHans Verkuil s->video_dev.fops = &cx18_v4l2_enc_fops; 36008569d64SHans Verkuil s->video_dev.release = video_device_release_empty; 3613a29a4f1SHans Verkuil if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER) 3623a29a4f1SHans Verkuil s->video_dev.tvnorms = cx->tuner_std; 3633a29a4f1SHans Verkuil else 36408569d64SHans Verkuil s->video_dev.tvnorms = V4L2_STD_ALL; 36508569d64SHans Verkuil s->video_dev.lock = &cx->serialize_lock; 36608569d64SHans Verkuil cx18_set_funcs(&s->video_dev); 367b285192aSMauro Carvalho Chehab return 0; 368b285192aSMauro Carvalho Chehab } 369b285192aSMauro Carvalho Chehab 370b285192aSMauro Carvalho Chehab /* Initialize v4l2 variables and register v4l2 devices */ 371b285192aSMauro Carvalho Chehab int cx18_streams_setup(struct cx18 *cx) 372b285192aSMauro Carvalho Chehab { 373b285192aSMauro Carvalho Chehab int type, ret; 374b285192aSMauro Carvalho Chehab 375b285192aSMauro Carvalho Chehab /* Setup V4L2 Devices */ 376b285192aSMauro Carvalho Chehab for (type = 0; type < CX18_MAX_STREAMS; type++) { 377b285192aSMauro Carvalho Chehab /* Prepare device */ 378b285192aSMauro Carvalho Chehab ret = cx18_prep_dev(cx, type); 379b285192aSMauro Carvalho Chehab if (ret < 0) 380b285192aSMauro Carvalho Chehab break; 381b285192aSMauro Carvalho Chehab 382b285192aSMauro Carvalho Chehab /* Allocate Stream */ 383b285192aSMauro Carvalho Chehab ret = cx18_stream_alloc(&cx->streams[type]); 384b285192aSMauro Carvalho Chehab if (ret < 0) 385b285192aSMauro Carvalho Chehab break; 386b285192aSMauro Carvalho Chehab } 387b285192aSMauro Carvalho Chehab if (type == CX18_MAX_STREAMS) 388b285192aSMauro Carvalho Chehab return 0; 389b285192aSMauro Carvalho Chehab 390b285192aSMauro Carvalho Chehab /* One or more streams could not be initialized. Clean 'em all up. */ 391b285192aSMauro Carvalho Chehab cx18_streams_cleanup(cx, 0); 392b285192aSMauro Carvalho Chehab return ret; 393b285192aSMauro Carvalho Chehab } 394b285192aSMauro Carvalho Chehab 395b285192aSMauro Carvalho Chehab static int cx18_reg_dev(struct cx18 *cx, int type) 396b285192aSMauro Carvalho Chehab { 397b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[type]; 398b285192aSMauro Carvalho Chehab int vfl_type = cx18_stream_info[type].vfl_type; 399b285192aSMauro Carvalho Chehab const char *name; 400b285192aSMauro Carvalho Chehab int num, ret; 401b285192aSMauro Carvalho Chehab 402b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) { 403b285192aSMauro Carvalho Chehab ret = cx18_dvb_register(s); 404b285192aSMauro Carvalho Chehab if (ret < 0) { 405b285192aSMauro Carvalho Chehab CX18_ERR("DVB failed to register\n"); 406b285192aSMauro Carvalho Chehab return ret; 407b285192aSMauro Carvalho Chehab } 408b285192aSMauro Carvalho Chehab } 409b285192aSMauro Carvalho Chehab 41008569d64SHans Verkuil if (s->video_dev.v4l2_dev == NULL) 411b285192aSMauro Carvalho Chehab return 0; 412b285192aSMauro Carvalho Chehab 41308569d64SHans Verkuil num = s->video_dev.num; 41421615365SHans Verkuil s->video_dev.device_caps = s->v4l2_dev_caps; /* device capabilities */ 415b285192aSMauro Carvalho Chehab /* card number + user defined offset + device offset */ 416b285192aSMauro Carvalho Chehab if (type != CX18_ENC_STREAM_TYPE_MPG) { 417b285192aSMauro Carvalho Chehab struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; 418b285192aSMauro Carvalho Chehab 41908569d64SHans Verkuil if (s_mpg->video_dev.v4l2_dev) 42008569d64SHans Verkuil num = s_mpg->video_dev.num 421b285192aSMauro Carvalho Chehab + cx18_stream_info[type].num_offset; 422b285192aSMauro Carvalho Chehab } 42308569d64SHans Verkuil video_set_drvdata(&s->video_dev, s); 424b285192aSMauro Carvalho Chehab 425b285192aSMauro Carvalho Chehab /* Register device. First try the desired minor, then any free one. */ 42608569d64SHans Verkuil ret = video_register_device_no_warn(&s->video_dev, vfl_type, num); 427b285192aSMauro Carvalho Chehab if (ret < 0) { 428b285192aSMauro Carvalho Chehab CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", 429b285192aSMauro Carvalho Chehab s->name, num); 43008569d64SHans Verkuil s->video_dev.v4l2_dev = NULL; 431b285192aSMauro Carvalho Chehab return ret; 432b285192aSMauro Carvalho Chehab } 433b285192aSMauro Carvalho Chehab 43408569d64SHans Verkuil name = video_device_node_name(&s->video_dev); 435b285192aSMauro Carvalho Chehab 436b285192aSMauro Carvalho Chehab switch (vfl_type) { 437*3e30a927SHans Verkuil case VFL_TYPE_VIDEO: 438b285192aSMauro Carvalho Chehab CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", 439b285192aSMauro Carvalho Chehab name, s->name, cx->stream_buffers[type], 440b285192aSMauro Carvalho Chehab cx->stream_buf_size[type] / 1024, 441b285192aSMauro Carvalho Chehab (cx->stream_buf_size[type] * 100 / 1024) % 100); 442b285192aSMauro Carvalho Chehab break; 443b285192aSMauro Carvalho Chehab 444b285192aSMauro Carvalho Chehab case VFL_TYPE_RADIO: 445b285192aSMauro Carvalho Chehab CX18_INFO("Registered device %s for %s\n", name, s->name); 446b285192aSMauro Carvalho Chehab break; 447b285192aSMauro Carvalho Chehab 448b285192aSMauro Carvalho Chehab case VFL_TYPE_VBI: 449b285192aSMauro Carvalho Chehab if (cx->stream_buffers[type]) 4506beb1388SMauro Carvalho Chehab CX18_INFO("Registered device %s for %s (%d x %d bytes)\n", 451b285192aSMauro Carvalho Chehab name, s->name, cx->stream_buffers[type], 452b285192aSMauro Carvalho Chehab cx->stream_buf_size[type]); 453b285192aSMauro Carvalho Chehab else 454b285192aSMauro Carvalho Chehab CX18_INFO("Registered device %s for %s\n", 455b285192aSMauro Carvalho Chehab name, s->name); 456b285192aSMauro Carvalho Chehab break; 457b285192aSMauro Carvalho Chehab } 458b285192aSMauro Carvalho Chehab 459b285192aSMauro Carvalho Chehab return 0; 460b285192aSMauro Carvalho Chehab } 461b285192aSMauro Carvalho Chehab 462b285192aSMauro Carvalho Chehab /* Register v4l2 devices */ 463b285192aSMauro Carvalho Chehab int cx18_streams_register(struct cx18 *cx) 464b285192aSMauro Carvalho Chehab { 465b285192aSMauro Carvalho Chehab int type; 466b285192aSMauro Carvalho Chehab int err; 467b285192aSMauro Carvalho Chehab int ret = 0; 468b285192aSMauro Carvalho Chehab 469b285192aSMauro Carvalho Chehab /* Register V4L2 devices */ 470b285192aSMauro Carvalho Chehab for (type = 0; type < CX18_MAX_STREAMS; type++) { 471b285192aSMauro Carvalho Chehab err = cx18_reg_dev(cx, type); 472b285192aSMauro Carvalho Chehab if (err && ret == 0) 473b285192aSMauro Carvalho Chehab ret = err; 474b285192aSMauro Carvalho Chehab } 475b285192aSMauro Carvalho Chehab 476b285192aSMauro Carvalho Chehab if (ret == 0) 477b285192aSMauro Carvalho Chehab return 0; 478b285192aSMauro Carvalho Chehab 479b285192aSMauro Carvalho Chehab /* One or more streams could not be initialized. Clean 'em all up. */ 480b285192aSMauro Carvalho Chehab cx18_streams_cleanup(cx, 1); 481b285192aSMauro Carvalho Chehab return ret; 482b285192aSMauro Carvalho Chehab } 483b285192aSMauro Carvalho Chehab 484b285192aSMauro Carvalho Chehab /* Unregister v4l2 devices */ 485b285192aSMauro Carvalho Chehab void cx18_streams_cleanup(struct cx18 *cx, int unregister) 486b285192aSMauro Carvalho Chehab { 487b285192aSMauro Carvalho Chehab struct video_device *vdev; 488b285192aSMauro Carvalho Chehab int type; 489b285192aSMauro Carvalho Chehab 490b285192aSMauro Carvalho Chehab /* Teardown all streams */ 491b285192aSMauro Carvalho Chehab for (type = 0; type < CX18_MAX_STREAMS; type++) { 492b285192aSMauro Carvalho Chehab 493b285192aSMauro Carvalho Chehab /* The TS has a cx18_dvb structure, not a video_device */ 494b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_TS) { 495b285192aSMauro Carvalho Chehab if (cx->streams[type].dvb != NULL) { 496b285192aSMauro Carvalho Chehab if (unregister) 497b285192aSMauro Carvalho Chehab cx18_dvb_unregister(&cx->streams[type]); 498b285192aSMauro Carvalho Chehab kfree(cx->streams[type].dvb); 499b285192aSMauro Carvalho Chehab cx->streams[type].dvb = NULL; 500b285192aSMauro Carvalho Chehab cx18_stream_free(&cx->streams[type]); 501b285192aSMauro Carvalho Chehab } 502b285192aSMauro Carvalho Chehab continue; 503b285192aSMauro Carvalho Chehab } 504b285192aSMauro Carvalho Chehab 505b285192aSMauro Carvalho Chehab /* No struct video_device, but can have buffers allocated */ 506b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_IDX) { 507b285192aSMauro Carvalho Chehab /* If the module params didn't inhibit IDX ... */ 508b285192aSMauro Carvalho Chehab if (cx->stream_buffers[type] != 0) { 509b285192aSMauro Carvalho Chehab cx->stream_buffers[type] = 0; 510b285192aSMauro Carvalho Chehab /* 511b285192aSMauro Carvalho Chehab * Before calling cx18_stream_free(), 512b285192aSMauro Carvalho Chehab * check if the IDX stream was actually set up. 513b285192aSMauro Carvalho Chehab * Needed, since the cx18_probe() error path 514b285192aSMauro Carvalho Chehab * exits through here as well as normal clean up 515b285192aSMauro Carvalho Chehab */ 516b285192aSMauro Carvalho Chehab if (cx->streams[type].buffers != 0) 517b285192aSMauro Carvalho Chehab cx18_stream_free(&cx->streams[type]); 518b285192aSMauro Carvalho Chehab } 519b285192aSMauro Carvalho Chehab continue; 520b285192aSMauro Carvalho Chehab } 521b285192aSMauro Carvalho Chehab 522b285192aSMauro Carvalho Chehab /* If struct video_device exists, can have buffers allocated */ 52308569d64SHans Verkuil vdev = &cx->streams[type].video_dev; 524b285192aSMauro Carvalho Chehab 52508569d64SHans Verkuil if (vdev->v4l2_dev == NULL) 526b285192aSMauro Carvalho Chehab continue; 527b285192aSMauro Carvalho Chehab 528b285192aSMauro Carvalho Chehab if (type == CX18_ENC_STREAM_TYPE_YUV) 529b285192aSMauro Carvalho Chehab videobuf_mmap_free(&cx->streams[type].vbuf_q); 530b285192aSMauro Carvalho Chehab 531b285192aSMauro Carvalho Chehab cx18_stream_free(&cx->streams[type]); 532b285192aSMauro Carvalho Chehab 533b285192aSMauro Carvalho Chehab video_unregister_device(vdev); 534b285192aSMauro Carvalho Chehab } 535b285192aSMauro Carvalho Chehab } 536b285192aSMauro Carvalho Chehab 537b285192aSMauro Carvalho Chehab static void cx18_vbi_setup(struct cx18_stream *s) 538b285192aSMauro Carvalho Chehab { 539b285192aSMauro Carvalho Chehab struct cx18 *cx = s->cx; 540b285192aSMauro Carvalho Chehab int raw = cx18_raw_vbi(cx); 541b285192aSMauro Carvalho Chehab u32 data[CX2341X_MBOX_MAX_DATA]; 542b285192aSMauro Carvalho Chehab int lines; 543b285192aSMauro Carvalho Chehab 544b285192aSMauro Carvalho Chehab if (cx->is_60hz) { 545b285192aSMauro Carvalho Chehab cx->vbi.count = 12; 546b285192aSMauro Carvalho Chehab cx->vbi.start[0] = 10; 547b285192aSMauro Carvalho Chehab cx->vbi.start[1] = 273; 548b285192aSMauro Carvalho Chehab } else { /* PAL/SECAM */ 549b285192aSMauro Carvalho Chehab cx->vbi.count = 18; 550b285192aSMauro Carvalho Chehab cx->vbi.start[0] = 6; 551b285192aSMauro Carvalho Chehab cx->vbi.start[1] = 318; 552b285192aSMauro Carvalho Chehab } 553b285192aSMauro Carvalho Chehab 554b285192aSMauro Carvalho Chehab /* setup VBI registers */ 555b285192aSMauro Carvalho Chehab if (raw) 556b285192aSMauro Carvalho Chehab v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi); 557b285192aSMauro Carvalho Chehab else 558b285192aSMauro Carvalho Chehab v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced); 559b285192aSMauro Carvalho Chehab 560b285192aSMauro Carvalho Chehab /* 561b285192aSMauro Carvalho Chehab * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw 562b285192aSMauro Carvalho Chehab * VBI when the first analog capture channel starts, as once it starts 563b285192aSMauro Carvalho Chehab * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup 564b285192aSMauro Carvalho Chehab * (i.e. for the VBI capture channels). We also send it for each 565b285192aSMauro Carvalho Chehab * analog capture channel anyway just to make sure we get the proper 566b285192aSMauro Carvalho Chehab * behavior 567b285192aSMauro Carvalho Chehab */ 568b285192aSMauro Carvalho Chehab if (raw) { 569b285192aSMauro Carvalho Chehab lines = cx->vbi.count * 2; 570b285192aSMauro Carvalho Chehab } else { 571b285192aSMauro Carvalho Chehab /* 572b285192aSMauro Carvalho Chehab * For 525/60 systems, according to the VIP 2 & BT.656 std: 573b285192aSMauro Carvalho Chehab * The EAV RP code's Field bit toggles on line 4, a few lines 574b285192aSMauro Carvalho Chehab * after the Vertcal Blank bit has already toggled. 575b285192aSMauro Carvalho Chehab * Tell the encoder to capture 21-4+1=18 lines per field, 576b285192aSMauro Carvalho Chehab * since we want lines 10 through 21. 577b285192aSMauro Carvalho Chehab * 578b285192aSMauro Carvalho Chehab * For 625/50 systems, according to the VIP 2 & BT.656 std: 579b285192aSMauro Carvalho Chehab * The EAV RP code's Field bit toggles on line 1, a few lines 580b285192aSMauro Carvalho Chehab * after the Vertcal Blank bit has already toggled. 581b285192aSMauro Carvalho Chehab * (We've actually set the digitizer so that the Field bit 582b285192aSMauro Carvalho Chehab * toggles on line 2.) Tell the encoder to capture 23-2+1=22 583b285192aSMauro Carvalho Chehab * lines per field, since we want lines 6 through 23. 584b285192aSMauro Carvalho Chehab */ 585b285192aSMauro Carvalho Chehab lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2; 586b285192aSMauro Carvalho Chehab } 587b285192aSMauro Carvalho Chehab 588b285192aSMauro Carvalho Chehab data[0] = s->handle; 589b285192aSMauro Carvalho Chehab /* Lines per field */ 590b285192aSMauro Carvalho Chehab data[1] = (lines / 2) | ((lines / 2) << 16); 591b285192aSMauro Carvalho Chehab /* bytes per line */ 592318de791SMauro Carvalho Chehab data[2] = (raw ? VBI_ACTIVE_SAMPLES 593318de791SMauro Carvalho Chehab : (cx->is_60hz ? VBI_HBLANK_SAMPLES_60HZ 594318de791SMauro Carvalho Chehab : VBI_HBLANK_SAMPLES_50HZ)); 595b285192aSMauro Carvalho Chehab /* Every X number of frames a VBI interrupt arrives 596b285192aSMauro Carvalho Chehab (frames as in 25 or 30 fps) */ 597b285192aSMauro Carvalho Chehab data[3] = 1; 598b285192aSMauro Carvalho Chehab /* 599b285192aSMauro Carvalho Chehab * Set the SAV/EAV RP codes to look for as start/stop points 600b285192aSMauro Carvalho Chehab * when in VIP-1.1 mode 601b285192aSMauro Carvalho Chehab */ 602b285192aSMauro Carvalho Chehab if (raw) { 603b285192aSMauro Carvalho Chehab /* 604b285192aSMauro Carvalho Chehab * Start codes for beginning of "active" line in vertical blank 605b285192aSMauro Carvalho Chehab * 0x20 ( VerticalBlank ) 606b285192aSMauro Carvalho Chehab * 0x60 ( EvenField VerticalBlank ) 607b285192aSMauro Carvalho Chehab */ 608b285192aSMauro Carvalho Chehab data[4] = 0x20602060; 609b285192aSMauro Carvalho Chehab /* 610b285192aSMauro Carvalho Chehab * End codes for end of "active" raw lines and regular lines 611b285192aSMauro Carvalho Chehab * 0x30 ( VerticalBlank HorizontalBlank) 612b285192aSMauro Carvalho Chehab * 0x70 ( EvenField VerticalBlank HorizontalBlank) 613b285192aSMauro Carvalho Chehab * 0x90 (Task HorizontalBlank) 614b285192aSMauro Carvalho Chehab * 0xd0 (Task EvenField HorizontalBlank) 615b285192aSMauro Carvalho Chehab */ 616b285192aSMauro Carvalho Chehab data[5] = 0x307090d0; 617b285192aSMauro Carvalho Chehab } else { 618b285192aSMauro Carvalho Chehab /* 619b285192aSMauro Carvalho Chehab * End codes for active video, we want data in the hblank region 620b285192aSMauro Carvalho Chehab * 0xb0 (Task 0 VerticalBlank HorizontalBlank) 621b285192aSMauro Carvalho Chehab * 0xf0 (Task EvenField VerticalBlank HorizontalBlank) 622b285192aSMauro Carvalho Chehab * 623b285192aSMauro Carvalho Chehab * Since the V bit is only allowed to toggle in the EAV RP code, 624b285192aSMauro Carvalho Chehab * just before the first active region line, these two 625b285192aSMauro Carvalho Chehab * are problematic: 626b285192aSMauro Carvalho Chehab * 0x90 (Task HorizontalBlank) 627b285192aSMauro Carvalho Chehab * 0xd0 (Task EvenField HorizontalBlank) 628b285192aSMauro Carvalho Chehab * 629b285192aSMauro Carvalho Chehab * We have set the digitzer such that we don't have to worry 630b285192aSMauro Carvalho Chehab * about these problem codes. 631b285192aSMauro Carvalho Chehab */ 632b285192aSMauro Carvalho Chehab data[4] = 0xB0F0B0F0; 633b285192aSMauro Carvalho Chehab /* 634b285192aSMauro Carvalho Chehab * Start codes for beginning of active line in vertical blank 635b285192aSMauro Carvalho Chehab * 0xa0 (Task VerticalBlank ) 636b285192aSMauro Carvalho Chehab * 0xe0 (Task EvenField VerticalBlank ) 637b285192aSMauro Carvalho Chehab */ 638b285192aSMauro Carvalho Chehab data[5] = 0xA0E0A0E0; 639b285192aSMauro Carvalho Chehab } 640b285192aSMauro Carvalho Chehab 641b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n", 642b285192aSMauro Carvalho Chehab data[0], data[1], data[2], data[3], data[4], data[5]); 643b285192aSMauro Carvalho Chehab 644b285192aSMauro Carvalho Chehab cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); 645b285192aSMauro Carvalho Chehab } 646b285192aSMauro Carvalho Chehab 647b285192aSMauro Carvalho Chehab void cx18_stream_rotate_idx_mdls(struct cx18 *cx) 648b285192aSMauro Carvalho Chehab { 649b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; 650b285192aSMauro Carvalho Chehab struct cx18_mdl *mdl; 651b285192aSMauro Carvalho Chehab 652b285192aSMauro Carvalho Chehab if (!cx18_stream_enabled(s)) 653b285192aSMauro Carvalho Chehab return; 654b285192aSMauro Carvalho Chehab 655b285192aSMauro Carvalho Chehab /* Return if the firmware is not running low on MDLs */ 656b285192aSMauro Carvalho Chehab if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >= 657b285192aSMauro Carvalho Chehab CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN) 658b285192aSMauro Carvalho Chehab return; 659b285192aSMauro Carvalho Chehab 660b285192aSMauro Carvalho Chehab /* Return if there are no MDLs to rotate back to the firmware */ 661b285192aSMauro Carvalho Chehab if (atomic_read(&s->q_full.depth) < 2) 662b285192aSMauro Carvalho Chehab return; 663b285192aSMauro Carvalho Chehab 664b285192aSMauro Carvalho Chehab /* 665b285192aSMauro Carvalho Chehab * Take the oldest IDX MDL still holding data, and discard its index 666b285192aSMauro Carvalho Chehab * entries by scheduling the MDL to go back to the firmware 667b285192aSMauro Carvalho Chehab */ 668b285192aSMauro Carvalho Chehab mdl = cx18_dequeue(s, &s->q_full); 669b285192aSMauro Carvalho Chehab if (mdl != NULL) 670b285192aSMauro Carvalho Chehab cx18_enqueue(s, mdl, &s->q_free); 671b285192aSMauro Carvalho Chehab } 672b285192aSMauro Carvalho Chehab 673b285192aSMauro Carvalho Chehab static 674b285192aSMauro Carvalho Chehab struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s, 675b285192aSMauro Carvalho Chehab struct cx18_mdl *mdl) 676b285192aSMauro Carvalho Chehab { 677b285192aSMauro Carvalho Chehab struct cx18 *cx = s->cx; 678b285192aSMauro Carvalho Chehab struct cx18_queue *q; 679b285192aSMauro Carvalho Chehab 680b285192aSMauro Carvalho Chehab /* Don't give it to the firmware, if we're not running a capture */ 681b285192aSMauro Carvalho Chehab if (s->handle == CX18_INVALID_TASK_HANDLE || 682b285192aSMauro Carvalho Chehab test_bit(CX18_F_S_STOPPING, &s->s_flags) || 683b285192aSMauro Carvalho Chehab !test_bit(CX18_F_S_STREAMING, &s->s_flags)) 684b285192aSMauro Carvalho Chehab return cx18_enqueue(s, mdl, &s->q_free); 685b285192aSMauro Carvalho Chehab 686b285192aSMauro Carvalho Chehab q = cx18_enqueue(s, mdl, &s->q_busy); 687b285192aSMauro Carvalho Chehab if (q != &s->q_busy) 688b285192aSMauro Carvalho Chehab return q; /* The firmware has the max MDLs it can handle */ 689b285192aSMauro Carvalho Chehab 690b285192aSMauro Carvalho Chehab cx18_mdl_sync_for_device(s, mdl); 691b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, 692b285192aSMauro Carvalho Chehab (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem, 693b285192aSMauro Carvalho Chehab s->bufs_per_mdl, mdl->id, s->mdl_size); 694b285192aSMauro Carvalho Chehab return q; 695b285192aSMauro Carvalho Chehab } 696b285192aSMauro Carvalho Chehab 697b285192aSMauro Carvalho Chehab static 698b285192aSMauro Carvalho Chehab void _cx18_stream_load_fw_queue(struct cx18_stream *s) 699b285192aSMauro Carvalho Chehab { 700b285192aSMauro Carvalho Chehab struct cx18_queue *q; 701b285192aSMauro Carvalho Chehab struct cx18_mdl *mdl; 702b285192aSMauro Carvalho Chehab 703b285192aSMauro Carvalho Chehab if (atomic_read(&s->q_free.depth) == 0 || 704b285192aSMauro Carvalho Chehab atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM) 705b285192aSMauro Carvalho Chehab return; 706b285192aSMauro Carvalho Chehab 707b285192aSMauro Carvalho Chehab /* Move from q_free to q_busy notifying the firmware, until the limit */ 708b285192aSMauro Carvalho Chehab do { 709b285192aSMauro Carvalho Chehab mdl = cx18_dequeue(s, &s->q_free); 710b285192aSMauro Carvalho Chehab if (mdl == NULL) 711b285192aSMauro Carvalho Chehab break; 712b285192aSMauro Carvalho Chehab q = _cx18_stream_put_mdl_fw(s, mdl); 713b285192aSMauro Carvalho Chehab } while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM 714b285192aSMauro Carvalho Chehab && q == &s->q_busy); 715b285192aSMauro Carvalho Chehab } 716b285192aSMauro Carvalho Chehab 717b285192aSMauro Carvalho Chehab void cx18_out_work_handler(struct work_struct *work) 718b285192aSMauro Carvalho Chehab { 719b285192aSMauro Carvalho Chehab struct cx18_stream *s = 720b285192aSMauro Carvalho Chehab container_of(work, struct cx18_stream, out_work_order); 721b285192aSMauro Carvalho Chehab 722b285192aSMauro Carvalho Chehab _cx18_stream_load_fw_queue(s); 723b285192aSMauro Carvalho Chehab } 724b285192aSMauro Carvalho Chehab 725b285192aSMauro Carvalho Chehab static void cx18_stream_configure_mdls(struct cx18_stream *s) 726b285192aSMauro Carvalho Chehab { 727b285192aSMauro Carvalho Chehab cx18_unload_queues(s); 728b285192aSMauro Carvalho Chehab 729b285192aSMauro Carvalho Chehab switch (s->type) { 730b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_YUV: 731b285192aSMauro Carvalho Chehab /* 732b285192aSMauro Carvalho Chehab * Height should be a multiple of 32 lines. 733b285192aSMauro Carvalho Chehab * Set the MDL size to the exact size needed for one frame. 734b285192aSMauro Carvalho Chehab * Use enough buffers per MDL to cover the MDL size 735b285192aSMauro Carvalho Chehab */ 736b285192aSMauro Carvalho Chehab if (s->pixelformat == V4L2_PIX_FMT_HM12) 737b285192aSMauro Carvalho Chehab s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; 738b285192aSMauro Carvalho Chehab else 739b285192aSMauro Carvalho Chehab s->mdl_size = 720 * s->cx->cxhdl.height * 2; 740b285192aSMauro Carvalho Chehab s->bufs_per_mdl = s->mdl_size / s->buf_size; 741b285192aSMauro Carvalho Chehab if (s->mdl_size % s->buf_size) 742b285192aSMauro Carvalho Chehab s->bufs_per_mdl++; 743b285192aSMauro Carvalho Chehab break; 744b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_VBI: 745b285192aSMauro Carvalho Chehab s->bufs_per_mdl = 1; 746b285192aSMauro Carvalho Chehab if (cx18_raw_vbi(s->cx)) { 747b285192aSMauro Carvalho Chehab s->mdl_size = (s->cx->is_60hz ? 12 : 18) 748318de791SMauro Carvalho Chehab * 2 * VBI_ACTIVE_SAMPLES; 749b285192aSMauro Carvalho Chehab } else { 750b285192aSMauro Carvalho Chehab /* 751b285192aSMauro Carvalho Chehab * See comment in cx18_vbi_setup() below about the 752b285192aSMauro Carvalho Chehab * extra lines we capture in sliced VBI mode due to 753b285192aSMauro Carvalho Chehab * the lines on which EAV RP codes toggle. 754b285192aSMauro Carvalho Chehab */ 755b285192aSMauro Carvalho Chehab s->mdl_size = s->cx->is_60hz 756318de791SMauro Carvalho Chehab ? (21 - 4 + 1) * 2 * VBI_HBLANK_SAMPLES_60HZ 757318de791SMauro Carvalho Chehab : (23 - 2 + 1) * 2 * VBI_HBLANK_SAMPLES_50HZ; 758b285192aSMauro Carvalho Chehab } 759b285192aSMauro Carvalho Chehab break; 760b285192aSMauro Carvalho Chehab default: 761b285192aSMauro Carvalho Chehab s->bufs_per_mdl = 1; 762b285192aSMauro Carvalho Chehab s->mdl_size = s->buf_size * s->bufs_per_mdl; 763b285192aSMauro Carvalho Chehab break; 764b285192aSMauro Carvalho Chehab } 765b285192aSMauro Carvalho Chehab 766b285192aSMauro Carvalho Chehab cx18_load_queues(s); 767b285192aSMauro Carvalho Chehab } 768b285192aSMauro Carvalho Chehab 769b285192aSMauro Carvalho Chehab int cx18_start_v4l2_encode_stream(struct cx18_stream *s) 770b285192aSMauro Carvalho Chehab { 771b285192aSMauro Carvalho Chehab u32 data[MAX_MB_ARGUMENTS]; 772b285192aSMauro Carvalho Chehab struct cx18 *cx = s->cx; 773b285192aSMauro Carvalho Chehab int captype = 0; 774b285192aSMauro Carvalho Chehab struct cx18_stream *s_idx; 775b285192aSMauro Carvalho Chehab 776b285192aSMauro Carvalho Chehab if (!cx18_stream_enabled(s)) 777b285192aSMauro Carvalho Chehab return -EINVAL; 778b285192aSMauro Carvalho Chehab 779b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); 780b285192aSMauro Carvalho Chehab 781b285192aSMauro Carvalho Chehab switch (s->type) { 782b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_MPG: 783b285192aSMauro Carvalho Chehab captype = CAPTURE_CHANNEL_TYPE_MPEG; 784b285192aSMauro Carvalho Chehab cx->mpg_data_received = cx->vbi_data_inserted = 0; 785b285192aSMauro Carvalho Chehab cx->dualwatch_jiffies = jiffies; 786b285192aSMauro Carvalho Chehab cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); 787b285192aSMauro Carvalho Chehab cx->search_pack_header = 0; 788b285192aSMauro Carvalho Chehab break; 789b285192aSMauro Carvalho Chehab 790b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_IDX: 791b285192aSMauro Carvalho Chehab captype = CAPTURE_CHANNEL_TYPE_INDEX; 792b285192aSMauro Carvalho Chehab break; 793b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_TS: 794b285192aSMauro Carvalho Chehab captype = CAPTURE_CHANNEL_TYPE_TS; 795b285192aSMauro Carvalho Chehab break; 796b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_YUV: 797b285192aSMauro Carvalho Chehab captype = CAPTURE_CHANNEL_TYPE_YUV; 798b285192aSMauro Carvalho Chehab break; 799b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_PCM: 800b285192aSMauro Carvalho Chehab captype = CAPTURE_CHANNEL_TYPE_PCM; 801b285192aSMauro Carvalho Chehab break; 802b285192aSMauro Carvalho Chehab case CX18_ENC_STREAM_TYPE_VBI: 803b285192aSMauro Carvalho Chehab #ifdef CX18_ENCODER_PARSES_SLICED 804b285192aSMauro Carvalho Chehab captype = cx18_raw_vbi(cx) ? 805b285192aSMauro Carvalho Chehab CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; 806b285192aSMauro Carvalho Chehab #else 807b285192aSMauro Carvalho Chehab /* 808b285192aSMauro Carvalho Chehab * Currently we set things up so that Sliced VBI from the 809b285192aSMauro Carvalho Chehab * digitizer is handled as Raw VBI by the encoder 810b285192aSMauro Carvalho Chehab */ 811b285192aSMauro Carvalho Chehab captype = CAPTURE_CHANNEL_TYPE_VBI; 812b285192aSMauro Carvalho Chehab #endif 813b285192aSMauro Carvalho Chehab cx->vbi.frame = 0; 814b285192aSMauro Carvalho Chehab cx->vbi.inserted_frame = 0; 815b285192aSMauro Carvalho Chehab memset(cx->vbi.sliced_mpeg_size, 816b285192aSMauro Carvalho Chehab 0, sizeof(cx->vbi.sliced_mpeg_size)); 817b285192aSMauro Carvalho Chehab break; 818b285192aSMauro Carvalho Chehab default: 819b285192aSMauro Carvalho Chehab return -EINVAL; 820b285192aSMauro Carvalho Chehab } 821b285192aSMauro Carvalho Chehab 822b285192aSMauro Carvalho Chehab /* Clear Streamoff flags in case left from last capture */ 823b285192aSMauro Carvalho Chehab clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); 824b285192aSMauro Carvalho Chehab 825b285192aSMauro Carvalho Chehab cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); 826b285192aSMauro Carvalho Chehab s->handle = data[0]; 827b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); 828b285192aSMauro Carvalho Chehab 829b285192aSMauro Carvalho Chehab /* 830b285192aSMauro Carvalho Chehab * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and 831b285192aSMauro Carvalho Chehab * set up all the parameters, as it is not obvious which parameters the 832b285192aSMauro Carvalho Chehab * firmware shares across capture channel types and which it does not. 833b285192aSMauro Carvalho Chehab * 834b285192aSMauro Carvalho Chehab * Some of the cx18_vapi() calls below apply to only certain capture 835b285192aSMauro Carvalho Chehab * channel types. We're hoping there's no harm in calling most of them 836b285192aSMauro Carvalho Chehab * anyway, as long as the values are all consistent. Setting some 837b285192aSMauro Carvalho Chehab * shared parameters will have no effect once an analog capture channel 838b285192aSMauro Carvalho Chehab * has started streaming. 839b285192aSMauro Carvalho Chehab */ 840b285192aSMauro Carvalho Chehab if (captype != CAPTURE_CHANNEL_TYPE_TS) { 841b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); 842b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); 843b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); 844b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); 845b285192aSMauro Carvalho Chehab 846b285192aSMauro Carvalho Chehab /* 847b285192aSMauro Carvalho Chehab * Audio related reset according to 8482ebe0bb3SMauro Carvalho Chehab * Documentation/media/v4l-drivers/cx2341x.rst 849b285192aSMauro Carvalho Chehab */ 850b285192aSMauro Carvalho Chehab if (atomic_read(&cx->ana_capturing) == 0) 851b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, 852b285192aSMauro Carvalho Chehab s->handle, 12); 853b285192aSMauro Carvalho Chehab 854b285192aSMauro Carvalho Chehab /* 855b285192aSMauro Carvalho Chehab * Number of lines for Field 1 & Field 2 according to 8562ebe0bb3SMauro Carvalho Chehab * Documentation/media/v4l-drivers/cx2341x.rst 857b285192aSMauro Carvalho Chehab * Field 1 is 312 for 625 line systems in BT.656 858b285192aSMauro Carvalho Chehab * Field 2 is 313 for 625 line systems in BT.656 859b285192aSMauro Carvalho Chehab */ 860b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, 861b285192aSMauro Carvalho Chehab s->handle, 312, 313); 862b285192aSMauro Carvalho Chehab 863b285192aSMauro Carvalho Chehab if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) 864b285192aSMauro Carvalho Chehab cx18_vbi_setup(s); 865b285192aSMauro Carvalho Chehab 866b285192aSMauro Carvalho Chehab /* 867b285192aSMauro Carvalho Chehab * Select to receive I, P, and B frame index entries, if the 868b285192aSMauro Carvalho Chehab * index stream is enabled. Otherwise disable index entry 869b285192aSMauro Carvalho Chehab * generation. 870b285192aSMauro Carvalho Chehab */ 871b285192aSMauro Carvalho Chehab s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; 872b285192aSMauro Carvalho Chehab cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, 873b285192aSMauro Carvalho Chehab s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); 874b285192aSMauro Carvalho Chehab 875b285192aSMauro Carvalho Chehab /* Call out to the common CX2341x API setup for user controls */ 876b285192aSMauro Carvalho Chehab cx->cxhdl.priv = s; 877b285192aSMauro Carvalho Chehab cx2341x_handler_setup(&cx->cxhdl); 878b285192aSMauro Carvalho Chehab 879b285192aSMauro Carvalho Chehab /* 880b285192aSMauro Carvalho Chehab * When starting a capture and we're set for radio, 881b285192aSMauro Carvalho Chehab * ensure the video is muted, despite the user control. 882b285192aSMauro Carvalho Chehab */ 883b285192aSMauro Carvalho Chehab if (!cx->cxhdl.video_mute && 884b285192aSMauro Carvalho Chehab test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) 885b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, 886b285192aSMauro Carvalho Chehab (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); 887b285192aSMauro Carvalho Chehab 888b285192aSMauro Carvalho Chehab /* Enable the Video Format Converter for UYVY 4:2:2 support, 889b285192aSMauro Carvalho Chehab * rather than the default HM12 Macroblovk 4:2:0 support. 890b285192aSMauro Carvalho Chehab */ 891b285192aSMauro Carvalho Chehab if (captype == CAPTURE_CHANNEL_TYPE_YUV) { 892b285192aSMauro Carvalho Chehab if (s->pixelformat == V4L2_PIX_FMT_UYVY) 893b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, 894b285192aSMauro Carvalho Chehab s->handle, 1); 895b285192aSMauro Carvalho Chehab else 896b285192aSMauro Carvalho Chehab /* If in doubt, default to HM12 */ 897b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, 898b285192aSMauro Carvalho Chehab s->handle, 0); 899b285192aSMauro Carvalho Chehab } 900b285192aSMauro Carvalho Chehab } 901b285192aSMauro Carvalho Chehab 902b285192aSMauro Carvalho Chehab if (atomic_read(&cx->tot_capturing) == 0) { 903b285192aSMauro Carvalho Chehab cx2341x_handler_set_busy(&cx->cxhdl, 1); 904b285192aSMauro Carvalho Chehab clear_bit(CX18_F_I_EOS, &cx->i_flags); 905b285192aSMauro Carvalho Chehab cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); 906b285192aSMauro Carvalho Chehab } 907b285192aSMauro Carvalho Chehab 908b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, 909b285192aSMauro Carvalho Chehab (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, 910b285192aSMauro Carvalho Chehab (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); 911b285192aSMauro Carvalho Chehab 912b285192aSMauro Carvalho Chehab /* Init all the cpu_mdls for this stream */ 913b285192aSMauro Carvalho Chehab cx18_stream_configure_mdls(s); 914b285192aSMauro Carvalho Chehab _cx18_stream_load_fw_queue(s); 915b285192aSMauro Carvalho Chehab 916b285192aSMauro Carvalho Chehab /* begin_capture */ 917b285192aSMauro Carvalho Chehab if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { 918b285192aSMauro Carvalho Chehab CX18_DEBUG_WARN("Error starting capture!\n"); 919b285192aSMauro Carvalho Chehab /* Ensure we're really not capturing before releasing MDLs */ 920b285192aSMauro Carvalho Chehab set_bit(CX18_F_S_STOPPING, &s->s_flags); 921b285192aSMauro Carvalho Chehab if (s->type == CX18_ENC_STREAM_TYPE_MPG) 922b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); 923b285192aSMauro Carvalho Chehab else 924b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); 925b285192aSMauro Carvalho Chehab clear_bit(CX18_F_S_STREAMING, &s->s_flags); 926b285192aSMauro Carvalho Chehab /* FIXME - CX18_F_S_STREAMOFF as well? */ 927b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); 928b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); 929b285192aSMauro Carvalho Chehab s->handle = CX18_INVALID_TASK_HANDLE; 930b285192aSMauro Carvalho Chehab clear_bit(CX18_F_S_STOPPING, &s->s_flags); 931b285192aSMauro Carvalho Chehab if (atomic_read(&cx->tot_capturing) == 0) { 932b285192aSMauro Carvalho Chehab set_bit(CX18_F_I_EOS, &cx->i_flags); 933b285192aSMauro Carvalho Chehab cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); 934b285192aSMauro Carvalho Chehab } 935b285192aSMauro Carvalho Chehab return -EINVAL; 936b285192aSMauro Carvalho Chehab } 937b285192aSMauro Carvalho Chehab 938b285192aSMauro Carvalho Chehab /* you're live! sit back and await interrupts :) */ 939b285192aSMauro Carvalho Chehab if (captype != CAPTURE_CHANNEL_TYPE_TS) 940b285192aSMauro Carvalho Chehab atomic_inc(&cx->ana_capturing); 941b285192aSMauro Carvalho Chehab atomic_inc(&cx->tot_capturing); 942b285192aSMauro Carvalho Chehab return 0; 943b285192aSMauro Carvalho Chehab } 944b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx18_start_v4l2_encode_stream); 945b285192aSMauro Carvalho Chehab 946b285192aSMauro Carvalho Chehab void cx18_stop_all_captures(struct cx18 *cx) 947b285192aSMauro Carvalho Chehab { 948b285192aSMauro Carvalho Chehab int i; 949b285192aSMauro Carvalho Chehab 950b285192aSMauro Carvalho Chehab for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { 951b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[i]; 952b285192aSMauro Carvalho Chehab 953b285192aSMauro Carvalho Chehab if (!cx18_stream_enabled(s)) 954b285192aSMauro Carvalho Chehab continue; 955b285192aSMauro Carvalho Chehab if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) 956b285192aSMauro Carvalho Chehab cx18_stop_v4l2_encode_stream(s, 0); 957b285192aSMauro Carvalho Chehab } 958b285192aSMauro Carvalho Chehab } 959b285192aSMauro Carvalho Chehab 960b285192aSMauro Carvalho Chehab int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) 961b285192aSMauro Carvalho Chehab { 962b285192aSMauro Carvalho Chehab struct cx18 *cx = s->cx; 963b285192aSMauro Carvalho Chehab 964b285192aSMauro Carvalho Chehab if (!cx18_stream_enabled(s)) 965b285192aSMauro Carvalho Chehab return -EINVAL; 966b285192aSMauro Carvalho Chehab 967b285192aSMauro Carvalho Chehab /* This function assumes that you are allowed to stop the capture 968b285192aSMauro Carvalho Chehab and that we are actually capturing */ 969b285192aSMauro Carvalho Chehab 970b285192aSMauro Carvalho Chehab CX18_DEBUG_INFO("Stop Capture\n"); 971b285192aSMauro Carvalho Chehab 972b285192aSMauro Carvalho Chehab if (atomic_read(&cx->tot_capturing) == 0) 973b285192aSMauro Carvalho Chehab return 0; 974b285192aSMauro Carvalho Chehab 975b285192aSMauro Carvalho Chehab set_bit(CX18_F_S_STOPPING, &s->s_flags); 976b285192aSMauro Carvalho Chehab if (s->type == CX18_ENC_STREAM_TYPE_MPG) 977b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); 978b285192aSMauro Carvalho Chehab else 979b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); 980b285192aSMauro Carvalho Chehab 981b285192aSMauro Carvalho Chehab if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { 982b285192aSMauro Carvalho Chehab CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); 983b285192aSMauro Carvalho Chehab } 984b285192aSMauro Carvalho Chehab 985b285192aSMauro Carvalho Chehab if (s->type != CX18_ENC_STREAM_TYPE_TS) 986b285192aSMauro Carvalho Chehab atomic_dec(&cx->ana_capturing); 987b285192aSMauro Carvalho Chehab atomic_dec(&cx->tot_capturing); 988b285192aSMauro Carvalho Chehab 989b285192aSMauro Carvalho Chehab /* Clear capture and no-read bits */ 990b285192aSMauro Carvalho Chehab clear_bit(CX18_F_S_STREAMING, &s->s_flags); 991b285192aSMauro Carvalho Chehab 992b285192aSMauro Carvalho Chehab /* Tell the CX23418 it can't use our buffers anymore */ 993b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); 994b285192aSMauro Carvalho Chehab 995b285192aSMauro Carvalho Chehab cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); 996b285192aSMauro Carvalho Chehab s->handle = CX18_INVALID_TASK_HANDLE; 997b285192aSMauro Carvalho Chehab clear_bit(CX18_F_S_STOPPING, &s->s_flags); 998b285192aSMauro Carvalho Chehab 999b285192aSMauro Carvalho Chehab if (atomic_read(&cx->tot_capturing) > 0) 1000b285192aSMauro Carvalho Chehab return 0; 1001b285192aSMauro Carvalho Chehab 1002b285192aSMauro Carvalho Chehab cx2341x_handler_set_busy(&cx->cxhdl, 0); 1003b285192aSMauro Carvalho Chehab cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); 1004b285192aSMauro Carvalho Chehab wake_up(&s->waitq); 1005b285192aSMauro Carvalho Chehab 1006b285192aSMauro Carvalho Chehab return 0; 1007b285192aSMauro Carvalho Chehab } 1008b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx18_stop_v4l2_encode_stream); 1009b285192aSMauro Carvalho Chehab 1010b285192aSMauro Carvalho Chehab u32 cx18_find_handle(struct cx18 *cx) 1011b285192aSMauro Carvalho Chehab { 1012b285192aSMauro Carvalho Chehab int i; 1013b285192aSMauro Carvalho Chehab 1014b285192aSMauro Carvalho Chehab /* find first available handle to be used for global settings */ 1015b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_MAX_STREAMS; i++) { 1016b285192aSMauro Carvalho Chehab struct cx18_stream *s = &cx->streams[i]; 1017b285192aSMauro Carvalho Chehab 101808569d64SHans Verkuil if (s->video_dev.v4l2_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) 1019b285192aSMauro Carvalho Chehab return s->handle; 1020b285192aSMauro Carvalho Chehab } 1021b285192aSMauro Carvalho Chehab return CX18_INVALID_TASK_HANDLE; 1022b285192aSMauro Carvalho Chehab } 1023b285192aSMauro Carvalho Chehab 1024b285192aSMauro Carvalho Chehab struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) 1025b285192aSMauro Carvalho Chehab { 1026b285192aSMauro Carvalho Chehab int i; 1027b285192aSMauro Carvalho Chehab struct cx18_stream *s; 1028b285192aSMauro Carvalho Chehab 1029b285192aSMauro Carvalho Chehab if (handle == CX18_INVALID_TASK_HANDLE) 1030b285192aSMauro Carvalho Chehab return NULL; 1031b285192aSMauro Carvalho Chehab 1032b285192aSMauro Carvalho Chehab for (i = 0; i < CX18_MAX_STREAMS; i++) { 1033b285192aSMauro Carvalho Chehab s = &cx->streams[i]; 1034b285192aSMauro Carvalho Chehab if (s->handle != handle) 1035b285192aSMauro Carvalho Chehab continue; 1036b285192aSMauro Carvalho Chehab if (cx18_stream_enabled(s)) 1037b285192aSMauro Carvalho Chehab return s; 1038b285192aSMauro Carvalho Chehab } 1039b285192aSMauro Carvalho Chehab return NULL; 1040b285192aSMauro Carvalho Chehab } 1041