blob: 0c11f314c62e24749561d5e19b30b0bc565a1302 [file] [log] [blame]
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001/*
2 * Driver for the Conexant CX25821 PCIe bridge
3 *
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03004 * Copyright (C) 2009 Conexant Systems Inc.
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03005 * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
6 * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03007 * Parts adapted/taken from Eduardo Moscoso Rubino
8 * Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com>
9 *
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030010 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 *
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
Joe Perches36d89f72010-11-07 17:48:21 -030027#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030029#include "cx25821-video.h"
30
31MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -030032MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030033MODULE_LICENSE("GPL");
34
Mauro Carvalho Chehab53e712d2009-09-13 11:39:12 -030035static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030036
37module_param_array(video_nr, int, NULL, 0444);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030038
39MODULE_PARM_DESC(video_nr, "video device numbers");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030040
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030041static unsigned int video_debug = VIDEO_DEBUG;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030042module_param(video_debug, int, 0644);
43MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
44
45static unsigned int irq_debug;
46module_param(irq_debug, int, 0644);
47MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
48
Hans Verkuil95c232a2013-04-13 07:41:29 -030049static unsigned int vid_limit = 16;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030050module_param(vid_limit, int, 0644);
51MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
52
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030053#define FORMAT_FLAGS_PACKED 0x01
54
Hans Verkuil95c232a2013-04-13 07:41:29 -030055static const struct cx25821_fmt formats[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030056 {
Mauro Carvalho Chehabd7d93382010-03-24 14:23:25 -030057 .name = "8 bpp, gray",
58 .fourcc = V4L2_PIX_FMT_GREY,
59 .depth = 8,
60 .flags = FORMAT_FLAGS_PACKED,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030061 }, {
Mauro Carvalho Chehabd7d93382010-03-24 14:23:25 -030062 .name = "4:1:1, packed, Y41P",
63 .fourcc = V4L2_PIX_FMT_Y41P,
64 .depth = 12,
65 .flags = FORMAT_FLAGS_PACKED,
66 }, {
67 .name = "4:2:2, packed, YUYV",
68 .fourcc = V4L2_PIX_FMT_YUYV,
69 .depth = 16,
70 .flags = FORMAT_FLAGS_PACKED,
71 }, {
72 .name = "4:2:2, packed, UYVY",
73 .fourcc = V4L2_PIX_FMT_UYVY,
74 .depth = 16,
75 .flags = FORMAT_FLAGS_PACKED,
76 }, {
77 .name = "4:2:0, YUV",
78 .fourcc = V4L2_PIX_FMT_YUV420,
79 .depth = 12,
80 .flags = FORMAT_FLAGS_PACKED,
81 },
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030082};
83
Hans Verkuil95c232a2013-04-13 07:41:29 -030084static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030085{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030086 unsigned int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030087
Leonid V. Fedorenchike313e1f2011-09-16 14:15:13 +080088 if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030089 return formats + 1;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -030090
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030091 for (i = 0; i < ARRAY_SIZE(formats); i++)
92 if (formats[i].fourcc == fourcc)
93 return formats + i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030094
Joe Perches36d89f72010-11-07 17:48:21 -030095 pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030096 return NULL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030097}
98
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030099void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
100 u32 count)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300101{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300102 struct cx25821_buffer *buf;
103 int bc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300104
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300105 for (bc = 0;; bc++) {
106 if (list_empty(&q->active)) {
107 dprintk(1, "bc=%d (=0: active empty)\n", bc);
108 break;
109 }
110
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300111 buf = list_entry(q->active.next, struct cx25821_buffer,
112 vb.queue);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300113
114 /* count comes from the hw and it is 16bit wide --
115 * this trick handles wrap-arounds correctly for
116 * up to 32767 buffers in flight... */
Leonid V. Fedorenchike313e1f2011-09-16 14:15:13 +0800117 if ((s16) (count - buf->count) < 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300118 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300119
Sakari Ailus8e6057b2012-09-15 15:14:42 -0300120 v4l2_get_timestamp(&buf->vb.ts);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300121 buf->vb.state = VIDEOBUF_DONE;
122 list_del(&buf->vb.queue);
123 wake_up(&buf->vb.done);
124 }
125
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300126 if (list_empty(&q->active))
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300127 del_timer(&q->timeout);
128 else
129 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
130 if (bc != 1)
Leonid V. Fedorenchik692cfb92011-09-16 14:14:36 +0800131 pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300132}
133
Hans Verkuil95c232a2013-04-13 07:41:29 -0300134static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300135{
Joe Perches36d89f72010-11-07 17:48:21 -0300136 dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
137 __func__, (unsigned int)norm, v4l2_norm_to_name(norm));
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300138
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300139 dev->tvnorm = norm;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300140
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300141 /* Tell the internal A/V decoder */
142 cx25821_call_all(dev, core, s_std, norm);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300143
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300144 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300145}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300146
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300147/*
148static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl)
149{
Leonid V. Fedorenchikc2c311f2011-09-16 14:14:37 +0800150 int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300151
Leonid V. Fedorenchikc2c311f2011-09-16 14:14:37 +0800152 if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1)
153 return -EINVAL;
154 for (i = 0; i < CX25821_CTLS; i++)
155 if (cx25821_ctls[i].v.id == qctrl->id)
156 break;
157 if (i == CX25821_CTLS) {
158 *qctrl = no_ctl;
159 return 0;
160 }
161 *qctrl = cx25821_ctls[i].v;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300162 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300163}
164*/
165
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300166/* resource management */
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800167int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
168 unsigned int bit)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300169{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300170 dprintk(1, "%s()\n", __func__);
171 if (fh->resources & bit)
172 /* have it already allocated */
173 return 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300174
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300175 /* is it free? */
176 mutex_lock(&dev->lock);
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800177 if (dev->channels[fh->channel_id].resources & bit) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300178 /* no, someone else uses it */
179 mutex_unlock(&dev->lock);
180 return 0;
181 }
182 /* it's free, grab it */
183 fh->resources |= bit;
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800184 dev->channels[fh->channel_id].resources |= bit;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300185 dprintk(1, "res: get %d\n", bit);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300186 mutex_unlock(&dev->lock);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300187 return 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300188}
189
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -0300190int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300191{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300192 return fh->resources & bit;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300193}
194
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300195int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300196{
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800197 return fh->dev->channels[fh->channel_id].resources & bit;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300198}
199
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800200void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
201 unsigned int bits)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300202{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300203 BUG_ON((fh->resources & bits) != bits);
204 dprintk(1, "%s()\n", __func__);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300205
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300206 mutex_lock(&dev->lock);
207 fh->resources &= ~bits;
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800208 dev->channels[fh->channel_id].resources &= ~bits;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300209 dprintk(1, "res: put %d\n", bits);
210 mutex_unlock(&dev->lock);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300211}
212
Hans Verkuil95c232a2013-04-13 07:41:29 -0300213static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300214{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300215 struct v4l2_routing route;
216 memset(&route, 0, sizeof(route));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300217
Joe Perches36d89f72010-11-07 17:48:21 -0300218 dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300219 __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0,
220 INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3);
221 dev->input = input;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300222
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300223 route.input = INPUT(input)->vmux;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300224
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300225 /* Tell the internal A/V decoder */
226 cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300227
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300228 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300229}
230
231int cx25821_start_video_dma(struct cx25821_dev *dev,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300232 struct cx25821_dmaqueue *q,
233 struct cx25821_buffer *buf,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300234 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300235{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300236 int tmp = 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300237
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300238 /* setup fifo + format */
239 cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300240
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300241 /* reset counter */
242 cx_write(channel->gpcnt_ctl, 3);
243 q->count = 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300244
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300245 /* enable irq */
246 cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
247 cx_set(channel->int_msk, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300248
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300249 /* start dma */
250 cx_write(channel->dma_ctl, 0x11); /* FIFO and RISC enable */
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300251
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300252 /* make sure upstream setting if any is reversed */
253 tmp = cx_read(VID_CH_MODE_SEL);
254 cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300255
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300256 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300257}
258
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300259static int cx25821_restart_video_queue(struct cx25821_dev *dev,
260 struct cx25821_dmaqueue *q,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300261 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300262{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300263 struct cx25821_buffer *buf, *prev;
264 struct list_head *item;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300265
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300266 if (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300267 buf = list_entry(q->active.next, struct cx25821_buffer,
268 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300269
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300270 cx25821_start_video_dma(dev, q, buf, channel);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300271
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300272 list_for_each(item, &q->active) {
273 buf = list_entry(item, struct cx25821_buffer, vb.queue);
274 buf->count = q->count++;
275 }
276
277 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
278 return 0;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300279 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300280
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300281 prev = NULL;
282 for (;;) {
283 if (list_empty(&q->queued))
284 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300285
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300286 buf = list_entry(q->queued.next, struct cx25821_buffer,
287 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300288
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300289 if (NULL == prev) {
290 list_move_tail(&buf->vb.queue, &q->active);
291 cx25821_start_video_dma(dev, q, buf, channel);
292 buf->vb.state = VIDEOBUF_ACTIVE;
293 buf->count = q->count++;
294 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
295 } else if (prev->vb.width == buf->vb.width &&
296 prev->vb.height == buf->vb.height &&
297 prev->fmt == buf->fmt) {
298 list_move_tail(&buf->vb.queue, &q->active);
299 buf->vb.state = VIDEOBUF_ACTIVE;
300 buf->count = q->count++;
301 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800302 prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300303 } else {
304 return 0;
305 }
306 prev = buf;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300307 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300308}
309
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300310static void cx25821_vid_timeout(unsigned long data)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300311{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300312 struct cx25821_data *timeout_data = (struct cx25821_data *)data;
313 struct cx25821_dev *dev = timeout_data->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300314 const struct sram_channel *channel = timeout_data->channel;
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800315 struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300316 struct cx25821_buffer *buf;
317 unsigned long flags;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300318
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800319 /* cx25821_sram_channel_dump(dev, channel); */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300320 cx_clear(channel->dma_ctl, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300321
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300322 spin_lock_irqsave(&dev->slock, flags);
323 while (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300324 buf = list_entry(q->active.next, struct cx25821_buffer,
325 vb.queue);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300326 list_del(&buf->vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300327
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300328 buf->vb.state = VIDEOBUF_ERROR;
329 wake_up(&buf->vb.done);
330 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300331
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300332 cx25821_restart_video_queue(dev, q, channel);
333 spin_unlock_irqrestore(&dev->slock, flags);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300334}
335
336int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
337{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300338 u32 count = 0;
339 int handled = 0;
340 u32 mask;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300341 const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300342
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300343 mask = cx_read(channel->int_msk);
344 if (0 == (status & mask))
345 return handled;
346
347 cx_write(channel->int_stat, status);
348
349 /* risc op code error */
350 if (status & (1 << 16)) {
Joe Perches36d89f72010-11-07 17:48:21 -0300351 pr_warn("%s, %s: video risc op code error\n",
352 dev->name, channel->name);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300353 cx_clear(channel->dma_ctl, 0x11);
354 cx25821_sram_channel_dump(dev, channel);
355 }
356
357 /* risc1 y */
358 if (status & FLD_VID_DST_RISC1) {
359 spin_lock(&dev->slock);
360 count = cx_read(channel->gpcnt);
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800361 cx25821_video_wakeup(dev, &dev->channels[channel->i].vidq,
362 count);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300363 spin_unlock(&dev->slock);
364 handled++;
365 }
366
367 /* risc2 y */
368 if (status & 0x10) {
369 dprintk(2, "stopper video\n");
370 spin_lock(&dev->slock);
Leonid V. Fedorenchik788d0f32011-09-16 14:14:39 +0800371 cx25821_restart_video_queue(dev,
372 &dev->channels[channel->i].vidq, channel);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300373 spin_unlock(&dev->slock);
374 handled++;
375 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300376 return handled;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300377}
378
Hans Verkuil95c232a2013-04-13 07:41:29 -0300379static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300380 unsigned int *size)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300381{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300382 struct cx25821_fh *fh = q->priv_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300383
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300384 *size = fh->fmt->depth * fh->width * fh->height >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300385
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300386 if (0 == *count)
387 *count = 32;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300388
Andreas Bombedab7e312010-03-21 16:02:45 -0300389 if (*size * *count > vid_limit * 1024 * 1024)
390 *count = (vid_limit * 1024 * 1024) / *size;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300391
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300392 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300393}
394
Hans Verkuil95c232a2013-04-13 07:41:29 -0300395static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300396 enum v4l2_field field)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300397{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300398 struct cx25821_fh *fh = q->priv_data;
399 struct cx25821_dev *dev = fh->dev;
400 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300401 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300402 int rc, init_buffer = 0;
Hans Verkuil30fdf032012-04-20 06:26:19 -0300403 u32 line0_offset;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300404 struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
405 int bpl_local = LINE_SIZE_D1;
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800406 int channel_opened = fh->channel_id;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300407
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300408 BUG_ON(NULL == fh->fmt);
409 if (fh->width < 48 || fh->width > 720 ||
410 fh->height < 32 || fh->height > 576)
411 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300412
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300413 buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300414
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300415 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
416 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300417
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300418 if (buf->fmt != fh->fmt ||
419 buf->vb.width != fh->width ||
420 buf->vb.height != fh->height || buf->vb.field != field) {
421 buf->fmt = fh->fmt;
422 buf->vb.width = fh->width;
423 buf->vb.height = fh->height;
424 buf->vb.field = field;
425 init_buffer = 1;
426 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300427
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300428 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
429 init_buffer = 1;
430 rc = videobuf_iolock(q, &buf->vb, NULL);
431 if (0 != rc) {
Joe Perches36d89f72010-11-07 17:48:21 -0300432 printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n"));
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300433 goto fail;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300434 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300435 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300436
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300437 dprintk(1, "init_buffer=%d\n", init_buffer);
438
439 if (init_buffer) {
440
441 channel_opened = dev->channel_opened;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +0800442 if (channel_opened < 0 || channel_opened > 7)
443 channel_opened = 7;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300444
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800445 if (dev->channels[channel_opened].pixel_formats ==
446 PIXEL_FRMT_411)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300447 buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
448 else
449 buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
450
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800451 if (dev->channels[channel_opened].pixel_formats ==
452 PIXEL_FRMT_411) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300453 bpl_local = buf->bpl;
454 } else {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800455 bpl_local = buf->bpl; /* Default */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300456
457 if (channel_opened >= 0 && channel_opened <= 7) {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800458 if (dev->channels[channel_opened]
459 .use_cif_resolution) {
Leonid V. Fedorenchikcd52b2c2011-10-22 01:43:53 -0300460 if (dev->tvnorm & V4L2_STD_PAL_BG ||
461 dev->tvnorm & V4L2_STD_PAL_DK)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300462 bpl_local = 352 << 1;
463 else
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300464 bpl_local = dev->channels[
465 channel_opened].
466 cif_width << 1;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300467 }
468 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300469 }
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300470
471 switch (buf->vb.field) {
472 case V4L2_FIELD_TOP:
473 cx25821_risc_buffer(dev->pci, &buf->risc,
474 dma->sglist, 0, UNSET,
475 buf->bpl, 0, buf->vb.height);
476 break;
477 case V4L2_FIELD_BOTTOM:
478 cx25821_risc_buffer(dev->pci, &buf->risc,
479 dma->sglist, UNSET, 0,
480 buf->bpl, 0, buf->vb.height);
481 break;
482 case V4L2_FIELD_INTERLACED:
483 /* All other formats are top field first */
484 line0_offset = 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300485 dprintk(1, "top field first\n");
486
487 cx25821_risc_buffer(dev->pci, &buf->risc,
488 dma->sglist, line0_offset,
489 bpl_local, bpl_local, bpl_local,
490 buf->vb.height >> 1);
491 break;
492 case V4L2_FIELD_SEQ_TB:
493 cx25821_risc_buffer(dev->pci, &buf->risc,
494 dma->sglist,
495 0, buf->bpl * (buf->vb.height >> 1),
496 buf->bpl, 0, buf->vb.height >> 1);
497 break;
498 case V4L2_FIELD_SEQ_BT:
499 cx25821_risc_buffer(dev->pci, &buf->risc,
500 dma->sglist,
501 buf->bpl * (buf->vb.height >> 1), 0,
502 buf->bpl, 0, buf->vb.height >> 1);
503 break;
504 default:
505 BUG();
506 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300507 }
508
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300509 dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
510 buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth,
511 fh->fmt->name, (unsigned long)buf->risc.dma);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300512
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300513 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300514
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300515 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300516
Leonid V. Fedorenchik2748f262011-09-16 14:14:34 +0800517fail:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300518 cx25821_free_buffer(q, buf);
519 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300520}
521
Hans Verkuil95c232a2013-04-13 07:41:29 -0300522static void cx25821_buffer_release(struct videobuf_queue *q,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800523 struct videobuf_buffer *vb)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300524{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300525 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300526 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300527
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300528 cx25821_free_buffer(q, buf);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300529}
530
Hans Verkuil95c232a2013-04-13 07:41:29 -0300531static struct videobuf_queue *get_queue(struct cx25821_fh *fh)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300532{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300533 switch (fh->type) {
534 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
535 return &fh->vidq;
536 default:
537 BUG();
538 return NULL;
539 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300540}
541
Hans Verkuil95c232a2013-04-13 07:41:29 -0300542static int cx25821_get_resource(struct cx25821_fh *fh, int resource)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300543{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300544 switch (fh->type) {
545 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
546 return resource;
547 default:
548 BUG();
549 return 0;
550 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300551}
552
Hans Verkuil95c232a2013-04-13 07:41:29 -0300553static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300554{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300555 struct cx25821_fh *fh = file->private_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300556
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300557 return videobuf_mmap_mapper(get_queue(fh), vma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300558}
559
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300560
561static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
562{
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800563 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300564 container_of(vb, struct cx25821_buffer, vb);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800565 struct cx25821_buffer *prev;
566 struct cx25821_fh *fh = vq->priv_data;
567 struct cx25821_dev *dev = fh->dev;
568 struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300569
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800570 /* add jump to stopper */
571 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
572 buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
573 buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300574
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800575 dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300576
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800577 if (!list_empty(&q->queued)) {
578 list_add_tail(&buf->vb.queue, &q->queued);
579 buf->vb.state = VIDEOBUF_QUEUED;
580 dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
581 buf->vb.i);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300582
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800583 } else if (list_empty(&q->active)) {
584 list_add_tail(&buf->vb.queue, &q->active);
585 cx25821_start_video_dma(dev, q, buf,
586 dev->channels[fh->channel_id].sram_channels);
587 buf->vb.state = VIDEOBUF_ACTIVE;
588 buf->count = q->count++;
589 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
590 dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
591 buf, buf->vb.i, buf->count, q->count);
592 } else {
593 prev = list_entry(q->active.prev, struct cx25821_buffer,
594 vb.queue);
595 if (prev->vb.width == buf->vb.width
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300596 && prev->vb.height == buf->vb.height
597 && prev->fmt == buf->fmt) {
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800598 list_add_tail(&buf->vb.queue, &q->active);
599 buf->vb.state = VIDEOBUF_ACTIVE;
600 buf->count = q->count++;
601 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300602
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800603 /* 64 bit bits 63-32 */
604 prev->risc.jmp[2] = cpu_to_le32(0);
605 dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
606 buf, buf->vb.i, buf->count);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300607
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800608 } else {
609 list_add_tail(&buf->vb.queue, &q->queued);
610 buf->vb.state = VIDEOBUF_QUEUED;
611 dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
612 buf->vb.i);
613 }
614 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300615
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800616 if (list_empty(&q->active))
617 dprintk(2, "active queue empty!\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300618}
619
620static struct videobuf_queue_ops cx25821_video_qops = {
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800621 .buf_setup = cx25821_buffer_setup,
622 .buf_prepare = cx25821_buffer_prepare,
623 .buf_queue = buffer_queue,
624 .buf_release = cx25821_buffer_release,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300625};
626
627static int video_open(struct file *file)
628{
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800629 struct video_device *vdev = video_devdata(file);
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300630 struct cx25821_dev *dev = video_drvdata(file);
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800631 struct cx25821_fh *fh;
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800632 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
633 u32 pix_format;
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300634 int ch_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300635
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800636 dprintk(1, "open dev=%s type=%s\n", video_device_node_name(vdev),
637 v4l2_type_names[type]);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300638
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300639 for (ch_id = 0; ch_id < MAX_VID_CHANNEL_NUM - 1; ch_id++)
Hans Verkuil467870c2013-04-13 08:18:00 -0300640 if (&dev->channels[ch_id].vdev == vdev)
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300641 break;
642
643 /* Can't happen */
644 if (ch_id >= MAX_VID_CHANNEL_NUM - 1)
645 return -ENODEV;
646
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800647 /* allocate + initialize per filehandle data */
648 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
649 if (NULL == fh)
650 return -ENOMEM;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300651
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800652 file->private_data = fh;
653 fh->dev = dev;
654 fh->type = type;
655 fh->width = 720;
656 fh->channel_id = ch_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300657
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800658 if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
659 fh->height = 576;
660 else
661 fh->height = 480;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300662
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800663 dev->channel_opened = fh->channel_id;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +0800664 if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411)
665 pix_format = V4L2_PIX_FMT_Y41P;
666 else
667 pix_format = V4L2_PIX_FMT_YUYV;
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800668 fh->fmt = cx25821_format_by_fourcc(pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300669
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800670 v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300671
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300672 videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev,
673 &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
674 V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
675 fh, NULL);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300676
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800677 dprintk(1, "post videobuf_queue_init()\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300678
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800679 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300680}
681
682static ssize_t video_read(struct file *file, char __user * data, size_t count,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300683 loff_t *ppos)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300684{
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800685 struct cx25821_fh *fh = file->private_data;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300686
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800687 switch (fh->type) {
688 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
689 if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
690 return -EBUSY;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300691
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800692 return videobuf_read_one(&fh->vidq, data, count, ppos,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300693 file->f_flags & O_NONBLOCK);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300694
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800695 default:
696 BUG();
697 return 0;
698 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300699}
700
701static unsigned int video_poll(struct file *file,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300702 struct poll_table_struct *wait)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300703{
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800704 struct cx25821_fh *fh = file->private_data;
705 struct cx25821_buffer *buf;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300706
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800707 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
708 /* streaming capture */
709 if (list_empty(&fh->vidq.stream))
710 return POLLERR;
711 buf = list_entry(fh->vidq.stream.next,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300712 struct cx25821_buffer, vb.stream);
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800713 } else {
714 /* read() capture */
715 buf = (struct cx25821_buffer *)fh->vidq.read_buf;
716 if (NULL == buf)
717 return POLLERR;
718 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300719
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800720 poll_wait(file, &buf->vb.done, wait);
721 if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
722 if (buf->vb.state == VIDEOBUF_DONE) {
723 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300724
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800725 if (dev && dev->channels[fh->channel_id]
726 .use_cif_resolution) {
727 u8 cam_id = *((char *)buf->vb.baddr + 3);
728 memcpy((char *)buf->vb.baddr,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300729 (char *)buf->vb.baddr + (fh->width * 2),
730 (fh->width * 2));
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800731 *((char *)buf->vb.baddr + 3) = cam_id;
732 }
733 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300734
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800735 return POLLIN | POLLRDNORM;
736 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300737
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800738 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300739}
740
741static int video_release(struct file *file)
742{
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800743 struct cx25821_fh *fh = file->private_data;
744 struct cx25821_dev *dev = fh->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300745 const struct sram_channel *sram_ch =
746 dev->channels[0].sram_channels;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300747
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800748 /* stop the risc engine and fifo */
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300749 cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300750
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800751 /* stop video capture */
752 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
753 videobuf_queue_cancel(&fh->vidq);
754 cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
755 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300756
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800757 if (fh->vidq.read_buf) {
758 cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
759 kfree(fh->vidq.read_buf);
760 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300761
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800762 videobuf_mmap_free(&fh->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300763
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800764 v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
765 file->private_data = NULL;
766 kfree(fh);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300767
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800768 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300769}
770
Hans Verkuil95c232a2013-04-13 07:41:29 -0300771/* VIDEO IOCTLS */
772static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
773 struct v4l2_format *f)
774{
775 struct cx25821_fh *fh = priv;
776
777 f->fmt.pix.width = fh->width;
778 f->fmt.pix.height = fh->height;
779 f->fmt.pix.field = fh->vidq.field;
780 f->fmt.pix.pixelformat = fh->fmt->fourcc;
781 f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3;
782 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
783
784 return 0;
785}
786
787static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
788 struct v4l2_format *f)
789{
790 const struct cx25821_fmt *fmt;
791 enum v4l2_field field;
792 unsigned int maxw, maxh;
793
794 fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
795 if (NULL == fmt)
796 return -EINVAL;
797
798 field = f->fmt.pix.field;
799 maxw = 720;
800 maxh = 576;
801
802 if (V4L2_FIELD_ANY == field) {
803 if (f->fmt.pix.height > maxh / 2)
804 field = V4L2_FIELD_INTERLACED;
805 else
806 field = V4L2_FIELD_TOP;
807 }
808
809 switch (field) {
810 case V4L2_FIELD_TOP:
811 case V4L2_FIELD_BOTTOM:
812 maxh = maxh / 2;
813 break;
814 case V4L2_FIELD_INTERLACED:
815 break;
816 default:
817 return -EINVAL;
818 }
819
820 f->fmt.pix.field = field;
821 if (f->fmt.pix.height < 32)
822 f->fmt.pix.height = 32;
823 if (f->fmt.pix.height > maxh)
824 f->fmt.pix.height = maxh;
825 if (f->fmt.pix.width < 48)
826 f->fmt.pix.width = 48;
827 if (f->fmt.pix.width > maxw)
828 f->fmt.pix.width = maxw;
829 f->fmt.pix.width &= ~0x03;
830 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
831 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
832
833 return 0;
834}
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300835static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
836{
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800837 struct cx25821_fh *fh = priv;
838 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300839
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800840 if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
841 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300842
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800843 if (unlikely(i != fh->type))
844 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300845
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800846 if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh,
847 RESOURCE_VIDEO0))))
848 return -EBUSY;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300849
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800850 return videobuf_streamon(get_queue(fh));
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300851}
852
853static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
854{
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800855 struct cx25821_fh *fh = priv;
856 struct cx25821_dev *dev = fh->dev;
857 int err, res;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300858
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800859 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
860 return -EINVAL;
861 if (i != fh->type)
862 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300863
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800864 res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
865 err = videobuf_streamoff(get_queue(fh));
866 if (err < 0)
867 return err;
868 cx25821_res_free(dev, fh, res);
869 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300870}
871
Hans Verkuil95c232a2013-04-13 07:41:29 -0300872static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
873{
874 if (tvnorm == V4L2_STD_PAL_BG) {
875 if (width == 352 || width == 720)
876 return 1;
877 else
878 return 0;
879 }
880
881 if (tvnorm == V4L2_STD_NTSC_M) {
882 if (width == 320 || width == 352 || width == 720)
883 return 1;
884 else
885 return 0;
886 }
887 return 0;
888}
889
890static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
891{
892 if (tvnorm == V4L2_STD_PAL_BG) {
893 if (height == 576 || height == 288)
894 return 1;
895 else
896 return 0;
897 }
898
899 if (tvnorm == V4L2_STD_NTSC_M) {
900 if (height == 480 || height == 240)
901 return 1;
902 else
903 return 0;
904 }
905
906 return 0;
907}
908
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300909static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800910 struct v4l2_format *f)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300911{
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800912 struct cx25821_fh *fh = priv;
913 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300914 struct v4l2_mbus_framefmt mbus_fmt;
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800915 int err;
916 int pix_format = PIXEL_FRMT_422;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300917
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800918 if (fh) {
919 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
920 fh->prio);
921 if (0 != err)
922 return err;
923 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300924
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800925 dprintk(2, "%s()\n", __func__);
926 err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300927
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800928 if (0 != err)
929 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300930
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800931 fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
932 fh->vidq.field = f->fmt.pix.field;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300933
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800934 /* check if width and height is valid based on set standard */
935 if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
936 fh->width = f->fmt.pix.width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300937
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800938 if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
939 fh->height = f->fmt.pix.height;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300940
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800941 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
942 pix_format = PIXEL_FRMT_411;
943 else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
944 pix_format = PIXEL_FRMT_422;
945 else
946 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300947
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800948 cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300949
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800950 /* check if cif resolution */
951 if (fh->width == 320 || fh->width == 352)
952 dev->channels[fh->channel_id].use_cif_resolution = 1;
953 else
954 dev->channels[fh->channel_id].use_cif_resolution = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300955
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800956 dev->channels[fh->channel_id].cif_width = fh->width;
957 medusa_set_resolution(dev, fh->width, SRAM_CH00);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300958
Joe Perches36d89f72010-11-07 17:48:21 -0300959 dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width,
960 fh->height, fh->vidq.field);
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300961 v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
962 cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300963
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800964 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300965}
966
967static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
968{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800969 int ret_val = 0;
970 struct cx25821_fh *fh = priv;
971 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300972
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800973 ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300974
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800975 p->sequence = dev->channels[fh->channel_id].vidq.count;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300976
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800977 return ret_val;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300978}
979
980static int vidioc_log_status(struct file *file, void *priv)
981{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800982 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
983 struct cx25821_fh *fh = priv;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300984 const struct sram_channel *sram_ch =
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300985 dev->channels[fh->channel_id].sram_channels;
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800986 u32 tmp = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300987
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800988 cx25821_call_all(dev, core, log_status);
989 tmp = cx_read(sram_ch->dma_ctl);
Joe Perches36d89f72010-11-07 17:48:21 -0300990 pr_info("Video input 0 is %s\n",
991 (tmp & 0x11) ? "streaming" : "stopped");
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800992 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300993}
994
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300995
Hans Verkuil95c232a2013-04-13 07:41:29 -0300996static int cx25821_vidioc_querycap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800997 struct v4l2_capability *cap)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300998{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300999 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuil3dd473c2013-04-13 06:06:18 -03001000 struct cx25821_fh *fh = priv;
1001 const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
1002 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
1003 const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001004
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001005 strcpy(cap->driver, "cx25821");
1006 strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
1007 sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
Hans Verkuil3dd473c2013-04-13 06:06:18 -03001008 if (fh->channel_id >= VID_CHANNEL_NUM)
1009 cap->device_caps = cap_output;
1010 else
1011 cap->device_caps = cap_input;
1012 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001013 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001014}
1015
Hans Verkuil95c232a2013-04-13 07:41:29 -03001016static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001017 struct v4l2_fmtdesc *f)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001018{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001019 if (unlikely(f->index >= ARRAY_SIZE(formats)))
1020 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001021
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001022 strlcpy(f->description, formats[f->index].name, sizeof(f->description));
1023 f->pixelformat = formats[f->index].fourcc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001024
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001025 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001026}
1027
Hans Verkuil95c232a2013-04-13 07:41:29 -03001028static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +08001029 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001030{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001031 struct cx25821_fh *fh = priv;
1032 return videobuf_reqbufs(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001033}
1034
Hans Verkuil95c232a2013-04-13 07:41:29 -03001035static int cx25821_vidioc_querybuf(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +08001036 struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001037{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001038 struct cx25821_fh *fh = priv;
1039 return videobuf_querybuf(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001040}
1041
Hans Verkuil95c232a2013-04-13 07:41:29 -03001042static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001043{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001044 struct cx25821_fh *fh = priv;
1045 return videobuf_qbuf(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001046}
1047
Hans Verkuil95c232a2013-04-13 07:41:29 -03001048static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001049{
1050 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001051 struct cx25821_fh *fh = f;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001052
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001053 *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001054
1055 return 0;
1056}
1057
Hans Verkuil95c232a2013-04-13 07:41:29 -03001058static int cx25821_vidioc_s_priority(struct file *file, void *f,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +08001059 enum v4l2_priority prio)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001060{
1061 struct cx25821_fh *fh = f;
1062 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
1063
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001064 return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio,
1065 prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001066}
1067
Hans Verkuil95c232a2013-04-13 07:41:29 -03001068static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
Hans Verkuil18c73af2013-04-13 05:50:18 -03001069{
1070 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1071
1072 *tvnorms = dev->tvnorm;
1073 return 0;
1074}
1075
Hans Verkuil314527a2013-03-15 06:10:40 -03001076int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001077{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001078 struct cx25821_fh *fh = priv;
1079 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1080 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001081
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001082 dprintk(1, "%s()\n", __func__);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001083
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001084 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001085 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1086 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001087 if (0 != err)
1088 return err;
1089 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001090
Hans Verkuil314527a2013-03-15 06:10:40 -03001091 if (dev->tvnorm == tvnorms)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001092 return 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001093
1094 mutex_lock(&dev->lock);
Hans Verkuil314527a2013-03-15 06:10:40 -03001095 cx25821_set_tvnorm(dev, tvnorms);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001096 mutex_unlock(&dev->lock);
1097
1098 medusa_set_videostandard(dev);
1099
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001100 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001101}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001102
Hans Verkuil95c232a2013-04-13 07:41:29 -03001103static int cx25821_vidioc_enum_input(struct file *file, void *priv,
1104 struct v4l2_input *i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001105{
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001106 static const char * const iname[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001107 [CX25821_VMUX_COMPOSITE] = "Composite",
1108 [CX25821_VMUX_SVIDEO] = "S-Video",
1109 [CX25821_VMUX_DEBUG] = "for debug only",
1110 };
Hans Verkuil95c232a2013-04-13 07:41:29 -03001111 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001112 unsigned int n;
1113 dprintk(1, "%s()\n", __func__);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001114
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001115 n = i->index;
Hans Verkuil95c232a2013-04-13 07:41:29 -03001116 if (n >= CX25821_NR_INPUT)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001117 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001118
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001119 if (0 == INPUT(n)->type)
1120 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001121
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001122 i->type = V4L2_INPUT_TYPE_CAMERA;
1123 strcpy(i->name, iname[INPUT(n)->type]);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001124
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001125 i->std = CX25821_NORMS;
1126 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001127}
1128
Hans Verkuil95c232a2013-04-13 07:41:29 -03001129static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001130{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001131 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001132
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001133 *i = dev->input;
Joe Perches36d89f72010-11-07 17:48:21 -03001134 dprintk(1, "%s(): returns %d\n", __func__, *i);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001135 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001136}
1137
Hans Verkuil95c232a2013-04-13 07:41:29 -03001138static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001139{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001140 struct cx25821_fh *fh = priv;
1141 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1142 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001143
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001144 dprintk(1, "%s(%d)\n", __func__, i);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001145
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001146 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001147 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1148 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001149 if (0 != err)
1150 return err;
1151 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001152
Hans Verkuil6b1dce22013-04-13 07:39:19 -03001153 if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001154 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001155
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001156 mutex_lock(&dev->lock);
1157 cx25821_video_mux(dev, i);
1158 mutex_unlock(&dev->lock);
1159 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001160}
1161
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001162#ifdef CONFIG_VIDEO_ADV_DEBUG
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001163int cx25821_vidioc_g_register(struct file *file, void *fh,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001164 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001165{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001166 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001167
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001168 if (!v4l2_chip_match_host(&reg->match))
1169 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001170
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001171 cx25821_call_all(dev, core, g_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001172
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001173 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001174}
1175
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001176int cx25821_vidioc_s_register(struct file *file, void *fh,
Hans Verkuil977ba3b2013-03-24 08:28:46 -03001177 const struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001178{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001179 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001180
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001181 if (!v4l2_chip_match_host(&reg->match))
1182 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001183
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001184 cx25821_call_all(dev, core, s_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001185
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001186 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001187}
1188
1189#endif
1190
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001191static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001192{
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001193 struct cx25821_channel *chan =
1194 container_of(ctrl->handler, struct cx25821_channel, hdl);
1195 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001196
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001197 switch (ctrl->id) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001198 case V4L2_CID_BRIGHTNESS:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001199 medusa_set_brightness(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001200 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001201 case V4L2_CID_HUE:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001202 medusa_set_hue(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001203 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001204 case V4L2_CID_CONTRAST:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001205 medusa_set_contrast(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001206 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001207 case V4L2_CID_SATURATION:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001208 medusa_set_saturation(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001209 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001210 default:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001211 return -EINVAL;
Joe Perches95cd17c2011-04-10 14:31:35 -07001212 }
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001213 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001214}
1215
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001216static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001217 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001218{
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001219 struct cx25821_fh *fh = file->private_data;
1220 struct cx25821_dev *dev = fh->dev;
1221 int command = 0;
1222 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001223
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001224 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001225
Joe Perches36d89f72010-11-07 17:48:21 -03001226 if (!data_from_user) {
1227 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1228 return 0;
1229 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001230
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001231 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001232
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001233 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1234 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001235
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001236 dev->input_filename = data_from_user->input_filename;
1237 dev->input_audiofilename = data_from_user->input_filename;
1238 dev->vid_stdname = data_from_user->vid_stdname;
1239 dev->pixel_format = data_from_user->pixel_format;
1240 dev->channel_select = data_from_user->channel_select;
1241 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001242
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001243 switch (command) {
1244 case UPSTREAM_START_VIDEO:
1245 cx25821_start_upstream_video_ch1(dev, data_from_user);
1246 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001247
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001248 case UPSTREAM_STOP_VIDEO:
1249 cx25821_stop_upstream_video_ch1(dev);
1250 break;
1251 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001252
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001253 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001254}
1255
1256static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001257 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001258{
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001259 struct cx25821_fh *fh = file->private_data;
1260 struct cx25821_dev *dev = fh->dev;
1261 int command = 0;
1262 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001263
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001264 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001265
Joe Perches36d89f72010-11-07 17:48:21 -03001266 if (!data_from_user) {
1267 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1268 return 0;
1269 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001270
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001271 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001272
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001273 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1274 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001275
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001276 dev->input_filename_ch2 = data_from_user->input_filename;
1277 dev->input_audiofilename = data_from_user->input_filename;
1278 dev->vid_stdname_ch2 = data_from_user->vid_stdname;
1279 dev->pixel_format_ch2 = data_from_user->pixel_format;
1280 dev->channel_select_ch2 = data_from_user->channel_select;
1281 dev->command_ch2 = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001282
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001283 switch (command) {
1284 case UPSTREAM_START_VIDEO:
1285 cx25821_start_upstream_video_ch2(dev, data_from_user);
1286 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001287
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001288 case UPSTREAM_STOP_VIDEO:
1289 cx25821_stop_upstream_video_ch2(dev);
1290 break;
1291 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001292
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001293 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001294}
1295
1296static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001297 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001298{
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001299 struct cx25821_fh *fh = file->private_data;
1300 struct cx25821_dev *dev = fh->dev;
1301 int command = 0;
1302 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001303
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001304 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001305
Joe Perches36d89f72010-11-07 17:48:21 -03001306 if (!data_from_user) {
1307 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1308 return 0;
1309 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001310
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001311 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001312
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001313 if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
1314 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001315
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001316 dev->input_filename = data_from_user->input_filename;
1317 dev->input_audiofilename = data_from_user->input_filename;
1318 dev->vid_stdname = data_from_user->vid_stdname;
1319 dev->pixel_format = data_from_user->pixel_format;
1320 dev->channel_select = data_from_user->channel_select;
1321 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001322
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001323 switch (command) {
1324 case UPSTREAM_START_AUDIO:
1325 cx25821_start_upstream_audio(dev, data_from_user);
1326 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001327
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001328 case UPSTREAM_STOP_AUDIO:
1329 cx25821_stop_upstream_audio(dev);
1330 break;
1331 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001332
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001333 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001334}
1335
1336static long video_ioctl_set(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001337 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001338{
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001339 struct cx25821_fh *fh = file->private_data;
1340 struct cx25821_dev *dev = fh->dev;
1341 struct downstream_user_struct *data_from_user;
1342 int command;
1343 int width = 720;
Leonid V. Fedorenchik4a33b6f2011-10-22 01:43:52 -03001344 int selected_channel = 0;
1345 int pix_format = 0;
1346 int i = 0;
1347 int cif_enable = 0;
1348 int cif_width = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001349
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001350 data_from_user = (struct downstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001351
Joe Perches36d89f72010-11-07 17:48:21 -03001352 if (!data_from_user) {
1353 pr_err("%s(): User data is INVALID. Returning\n", __func__);
1354 return 0;
1355 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001356
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001357 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001358
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001359 if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001360 && command != ENABLE_CIF_RESOLUTION && command != REG_READ
1361 && command != REG_WRITE && command != MEDUSA_READ
1362 && command != MEDUSA_WRITE) {
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001363 return 0;
1364 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001365
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001366 switch (command) {
1367 case SET_VIDEO_STD:
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001368 if (!strcmp(data_from_user->vid_stdname, "PAL"))
1369 dev->tvnorm = V4L2_STD_PAL_BG;
1370 else
1371 dev->tvnorm = V4L2_STD_NTSC_M;
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001372 medusa_set_videostandard(dev);
1373 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001374
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001375 case SET_PIXEL_FORMAT:
1376 selected_channel = data_from_user->decoder_select;
1377 pix_format = data_from_user->pixel_format;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001378
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001379 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1380 selected_channel -= 4;
1381 selected_channel = selected_channel % 8;
1382 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001383
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001384 if (selected_channel >= 0)
1385 cx25821_set_pixel_format(dev, selected_channel,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001386 pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001387
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001388 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001389
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001390 case ENABLE_CIF_RESOLUTION:
1391 selected_channel = data_from_user->decoder_select;
1392 cif_enable = data_from_user->cif_resolution_enable;
1393 cif_width = data_from_user->cif_width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001394
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001395 if (cif_enable) {
1396 if (dev->tvnorm & V4L2_STD_PAL_BG
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001397 || dev->tvnorm & V4L2_STD_PAL_DK) {
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001398 width = 352;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001399 } else {
1400 width = cif_width;
1401 if (cif_width != 320 && cif_width != 352)
1402 width = 320;
1403 }
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001404 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001405
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001406 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1407 selected_channel -= 4;
1408 selected_channel = selected_channel % 8;
1409 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001410
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001411 if (selected_channel <= 7 && selected_channel >= 0) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -03001412 dev->channels[selected_channel].use_cif_resolution =
1413 cif_enable;
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001414 dev->channels[selected_channel].cif_width = width;
1415 } else {
1416 for (i = 0; i < VID_CHANNEL_NUM; i++) {
1417 dev->channels[i].use_cif_resolution =
1418 cif_enable;
1419 dev->channels[i].cif_width = width;
1420 }
1421 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001422
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001423 medusa_set_resolution(dev, width, selected_channel);
1424 break;
1425 case REG_READ:
1426 data_from_user->reg_data = cx_read(data_from_user->reg_address);
1427 break;
1428 case REG_WRITE:
1429 cx_write(data_from_user->reg_address, data_from_user->reg_data);
1430 break;
1431 case MEDUSA_READ:
Hans Verkuil30fdf032012-04-20 06:26:19 -03001432 cx25821_i2c_read(&dev->i2c_bus[0],
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001433 (u16) data_from_user->reg_address,
1434 &data_from_user->reg_data);
1435 break;
1436 case MEDUSA_WRITE:
1437 cx25821_i2c_write(&dev->i2c_bus[0],
1438 (u16) data_from_user->reg_address,
1439 data_from_user->reg_data);
1440 break;
1441 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001442
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001443 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001444}
1445
1446static long cx25821_video_ioctl(struct file *file,
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001447 unsigned int cmd, unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001448{
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001449 int ret = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001450
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001451 struct cx25821_fh *fh = file->private_data;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001452
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001453 /* check to see if it's the video upstream */
1454 if (fh->channel_id == SRAM_CH09) {
1455 ret = video_ioctl_upstream9(file, cmd, arg);
1456 return ret;
1457 } else if (fh->channel_id == SRAM_CH10) {
1458 ret = video_ioctl_upstream10(file, cmd, arg);
1459 return ret;
1460 } else if (fh->channel_id == SRAM_CH11) {
1461 ret = video_ioctl_upstream11(file, cmd, arg);
1462 ret = video_ioctl_set(file, cmd, arg);
1463 return ret;
1464 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001465
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001466 return video_ioctl2(file, cmd, arg);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001467}
1468
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001469static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
1470 .s_ctrl = cx25821_s_ctrl,
1471};
1472
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001473static const struct v4l2_file_operations video_fops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001474 .owner = THIS_MODULE,
1475 .open = video_open,
1476 .release = video_release,
1477 .read = video_read,
1478 .poll = video_poll,
1479 .mmap = cx25821_video_mmap,
1480 .ioctl = cx25821_video_ioctl,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001481};
1482
1483static const struct v4l2_ioctl_ops video_ioctl_ops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001484 .vidioc_querycap = cx25821_vidioc_querycap,
1485 .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
1486 .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
1487 .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
1488 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1489 .vidioc_reqbufs = cx25821_vidioc_reqbufs,
1490 .vidioc_querybuf = cx25821_vidioc_querybuf,
1491 .vidioc_qbuf = cx25821_vidioc_qbuf,
1492 .vidioc_dqbuf = vidioc_dqbuf,
Hans Verkuil18c73af2013-04-13 05:50:18 -03001493 .vidioc_g_std = cx25821_vidioc_g_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001494 .vidioc_s_std = cx25821_vidioc_s_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001495 .vidioc_enum_input = cx25821_vidioc_enum_input,
1496 .vidioc_g_input = cx25821_vidioc_g_input,
1497 .vidioc_s_input = cx25821_vidioc_s_input,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001498 .vidioc_streamon = vidioc_streamon,
1499 .vidioc_streamoff = vidioc_streamoff,
1500 .vidioc_log_status = vidioc_log_status,
1501 .vidioc_g_priority = cx25821_vidioc_g_priority,
1502 .vidioc_s_priority = cx25821_vidioc_s_priority,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001503#ifdef CONFIG_VIDEO_ADV_DEBUG
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001504 .vidioc_g_register = cx25821_vidioc_g_register,
1505 .vidioc_s_register = cx25821_vidioc_s_register,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001506#endif
1507};
1508
Hans Verkuilffd3c232013-04-13 05:30:48 -03001509static const struct video_device cx25821_video_device = {
1510 .name = "cx25821-video",
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001511 .fops = &video_fops,
Hans Verkuil467870c2013-04-13 08:18:00 -03001512 .release = video_device_release_empty,
Hans Verkuilffd3c232013-04-13 05:30:48 -03001513 .minor = -1,
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001514 .ioctl_ops = &video_ioctl_ops,
1515 .tvnorms = CX25821_NORMS,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001516};
Hans Verkuilffd3c232013-04-13 05:30:48 -03001517
1518void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
1519{
1520 cx_clear(PCI_INT_MSK, 1);
1521
Hans Verkuil467870c2013-04-13 08:18:00 -03001522 if (video_is_registered(&dev->channels[chan_num].vdev)) {
1523 video_unregister_device(&dev->channels[chan_num].vdev);
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001524 v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001525
1526 btcx_riscmem_free(dev->pci,
1527 &dev->channels[chan_num].vidq.stopper);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001528 }
Hans Verkuilffd3c232013-04-13 05:30:48 -03001529}
1530
1531int cx25821_video_register(struct cx25821_dev *dev)
1532{
1533 int err;
1534 int i;
1535
1536 spin_lock_init(&dev->slock);
1537
1538 for (i = 0; i < VID_CHANNEL_NUM; ++i) {
Hans Verkuil467870c2013-04-13 08:18:00 -03001539 struct video_device *vdev = &dev->channels[i].vdev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001540 struct v4l2_ctrl_handler *hdl = &dev->channels[i].hdl;
Hans Verkuil467870c2013-04-13 08:18:00 -03001541
Hans Verkuilffd3c232013-04-13 05:30:48 -03001542 if (i == SRAM_CH08) /* audio channel */
1543 continue;
1544
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001545 v4l2_ctrl_handler_init(hdl, 4);
1546 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1547 V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
1548 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1549 V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
1550 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1551 V4L2_CID_SATURATION, 0, 10000, 1, 5000);
1552 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1553 V4L2_CID_HUE, 0, 10000, 1, 5000);
1554 if (hdl->error) {
1555 err = hdl->error;
1556 goto fail_unreg;
1557 }
Hans Verkuilffd3c232013-04-13 05:30:48 -03001558
1559 cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
1560 dev->channels[i].sram_channels->dma_ctl, 0x11, 0);
1561
1562 dev->channels[i].sram_channels = &cx25821_sram_channels[i];
Hans Verkuilffd3c232013-04-13 05:30:48 -03001563 dev->channels[i].resources = 0;
1564
1565 cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
1566
1567 INIT_LIST_HEAD(&dev->channels[i].vidq.active);
1568 INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
1569
1570 dev->channels[i].timeout_data.dev = dev;
1571 dev->channels[i].timeout_data.channel =
1572 &cx25821_sram_channels[i];
1573 dev->channels[i].vidq.timeout.function = cx25821_vid_timeout;
1574 dev->channels[i].vidq.timeout.data =
1575 (unsigned long)&dev->channels[i].timeout_data;
1576 init_timer(&dev->channels[i].vidq.timeout);
1577
1578 /* register v4l devices */
Hans Verkuil467870c2013-04-13 08:18:00 -03001579 *vdev = cx25821_video_device;
1580 vdev->v4l2_dev = &dev->v4l2_dev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001581 vdev->ctrl_handler = hdl;
Hans Verkuil467870c2013-04-13 08:18:00 -03001582 snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
1583 video_set_drvdata(vdev, dev);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001584
Hans Verkuil467870c2013-04-13 08:18:00 -03001585 err = video_register_device(vdev, VFL_TYPE_GRABBER,
1586 video_nr[dev->nr]);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001587
1588 if (err < 0)
1589 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001590 }
1591
1592 /* set PCI interrupt */
1593 cx_set(PCI_INT_MSK, 0xff);
1594
1595 /* initial device configuration */
1596 mutex_lock(&dev->lock);
Hans Verkuil18c73af2013-04-13 05:50:18 -03001597 dev->tvnorm = V4L2_STD_NTSC_M,
Hans Verkuilffd3c232013-04-13 05:30:48 -03001598 cx25821_set_tvnorm(dev, dev->tvnorm);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001599 mutex_unlock(&dev->lock);
1600
1601 return 0;
1602
1603fail_unreg:
Hans Verkuil467870c2013-04-13 08:18:00 -03001604 while (i >= 0)
1605 cx25821_video_unregister(dev, i--);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001606 return err;
1607}