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