2 * Driver for the Conexant CX25821 PCIe bridge
4 * Copyright (C) 2009 Conexant Systems Inc.
5 * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
6 * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "cx25821-video.h"
27 static void buffer_queue(struct videobuf_queue
*vq
, struct videobuf_buffer
*vb
)
29 struct cx25821_buffer
*buf
= container_of(vb
, struct cx25821_buffer
, vb
);
30 struct cx25821_buffer
*prev
;
31 struct cx25821_fh
*fh
= vq
->priv_data
;
32 struct cx25821_dev
*dev
= fh
->dev
;
33 struct cx25821_dmaqueue
*q
= &dev
->vidq
[SRAM_CH07
];
35 /* add jump to stopper */
36 buf
->risc
.jmp
[0] = cpu_to_le32(RISC_JUMP
| RISC_IRQ1
| RISC_CNT_INC
);
37 buf
->risc
.jmp
[1] = cpu_to_le32(q
->stopper
.dma
);
38 buf
->risc
.jmp
[2] = cpu_to_le32(0); /* bits 63-32 */
40 dprintk(2, "jmp to stopper (0x%x)\n", buf
->risc
.jmp
[1]);
41 if (!list_empty(&q
->queued
)) {
42 list_add_tail(&buf
->vb
.queue
, &q
->queued
);
43 buf
->vb
.state
= VIDEOBUF_QUEUED
;
44 dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf
, buf
->vb
.i
);
46 } else if (list_empty(&q
->active
)) {
47 list_add_tail(&buf
->vb
.queue
, &q
->active
);
48 cx25821_start_video_dma(dev
, q
, buf
, &dev
->sram_channels
[SRAM_CH07
]);
49 buf
->vb
.state
= VIDEOBUF_ACTIVE
;
50 buf
->count
= q
->count
++;
51 mod_timer(&q
->timeout
, jiffies
+BUFFER_TIMEOUT
);
52 dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
53 buf
, buf
->vb
. i
, buf
->count
, q
->count
);
55 prev
= list_entry(q
->active
.prev
, struct cx25821_buffer
, vb
.queue
);
56 if (prev
->vb
.width
== buf
->vb
.width
&&
57 prev
->vb
.height
== buf
->vb
.height
&&
58 prev
->fmt
== buf
->fmt
) {
59 list_add_tail(&buf
->vb
.queue
, &q
->active
);
60 buf
->vb
.state
= VIDEOBUF_ACTIVE
;
61 buf
->count
= q
->count
++;
62 prev
->risc
.jmp
[1] = cpu_to_le32(buf
->risc
.dma
);
64 /* 64 bit bits 63-32 */
65 prev
->risc
.jmp
[2] = cpu_to_le32(0);
66 dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n", buf
, buf
->vb
.i
, buf
->count
);
69 list_add_tail(&buf
->vb
.queue
, &q
->queued
);
70 buf
->vb
.state
= VIDEOBUF_QUEUED
;
71 dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf
, buf
->vb
.i
);
75 if (list_empty(&q
->active
))
77 dprintk(2, "active queue empty!\n");
82 static struct videobuf_queue_ops cx25821_video_qops
= {
83 .buf_setup
= buffer_setup
,
84 .buf_prepare
= buffer_prepare
,
85 .buf_queue
= buffer_queue
,
86 .buf_release
= buffer_release
,
90 static int video_open(struct file
*file
)
92 int minor
= video_devdata(file
)->minor
;
93 struct cx25821_dev
*h
, *dev
= NULL
;
94 struct cx25821_fh
*fh
;
95 struct list_head
*list
;
96 enum v4l2_buf_type type
= 0;
100 list_for_each(list
, &cx25821_devlist
)
102 h
= list_entry(list
, struct cx25821_dev
, devlist
);
104 if (h
->video_dev
[SRAM_CH07
] && h
->video_dev
[SRAM_CH07
]->minor
== minor
) {
106 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
115 printk("open minor=%d type=%s\n", minor
, v4l2_type_names
[type
]);
117 /* allocate + initialize per filehandle data */
118 fh
= kzalloc(sizeof(*fh
), GFP_KERNEL
);
123 file
->private_data
= fh
;
128 if(dev
->tvnorm
& V4L2_STD_PAL_BG
|| dev
->tvnorm
& V4L2_STD_PAL_DK
)
133 dev
->channel_opened
= SRAM_CH07
;
134 pix_format
= (dev
->pixel_formats
[dev
->channel_opened
] == PIXEL_FRMT_411
) ? V4L2_PIX_FMT_Y41P
: V4L2_PIX_FMT_YUYV
;
135 fh
->fmt
= format_by_fourcc(pix_format
);
137 v4l2_prio_open(&dev
->prio
,&fh
->prio
);
139 videobuf_queue_sg_init(&fh
->vidq
, &cx25821_video_qops
,
140 &dev
->pci
->dev
, &dev
->slock
,
141 V4L2_BUF_TYPE_VIDEO_CAPTURE
,
142 V4L2_FIELD_INTERLACED
,
143 sizeof(struct cx25821_buffer
),
146 dprintk(1, "post videobuf_queue_init()\n");
152 static ssize_t
video_read(struct file
*file
, char __user
*data
, size_t count
, loff_t
*ppos
)
154 struct cx25821_fh
*fh
= file
->private_data
;
158 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
159 if (res_locked(fh
->dev
, RESOURCE_VIDEO7
))
162 return videobuf_read_one(&fh
->vidq
, data
, count
, ppos
, file
->f_flags
& O_NONBLOCK
);
170 static unsigned int video_poll(struct file
*file
, struct poll_table_struct
*wait
)
172 struct cx25821_fh
*fh
= file
->private_data
;
173 struct cx25821_buffer
*buf
;
175 if (res_check(fh
, RESOURCE_VIDEO7
)) {
176 /* streaming capture */
177 if (list_empty(&fh
->vidq
.stream
))
179 buf
= list_entry(fh
->vidq
.stream
.next
,
180 struct cx25821_buffer
, vb
.stream
);
183 buf
= (struct cx25821_buffer
*)fh
->vidq
.read_buf
;
188 poll_wait(file
, &buf
->vb
.done
, wait
);
189 if (buf
->vb
.state
== VIDEOBUF_DONE
|| buf
->vb
.state
== VIDEOBUF_ERROR
)
191 if( buf
->vb
.state
== VIDEOBUF_DONE
)
193 struct cx25821_dev
*dev
= fh
->dev
;
195 if( dev
&& dev
->use_cif_resolution
[SRAM_CH07
] )
197 u8 cam_id
= *((char*)buf
->vb
.baddr
+3);
198 memcpy((char*)buf
->vb
.baddr
, (char*)buf
->vb
.baddr
+ (fh
->width
* 2), (fh
->width
* 2));
199 *((char*)buf
->vb
.baddr
+3) = cam_id
;
203 return POLLIN
|POLLRDNORM
;
210 static int video_release(struct file
*file
)
212 struct cx25821_fh
*fh
= file
->private_data
;
213 struct cx25821_dev
*dev
= fh
->dev
;
215 //stop the risc engine and fifo
216 cx_write(channel7
->dma_ctl
, 0); /* FIFO and RISC disable */
218 /* stop video capture */
219 if (res_check(fh
, RESOURCE_VIDEO7
)) {
220 videobuf_queue_cancel(&fh
->vidq
);
221 res_free(dev
, fh
, RESOURCE_VIDEO7
);
224 if (fh
->vidq
.read_buf
) {
225 buffer_release(&fh
->vidq
, fh
->vidq
.read_buf
);
226 kfree(fh
->vidq
.read_buf
);
229 videobuf_mmap_free(&fh
->vidq
);
231 v4l2_prio_close(&dev
->prio
,&fh
->prio
);
232 file
->private_data
= NULL
;
239 static int vidioc_streamon(struct file
*file
, void *priv
, enum v4l2_buf_type i
)
241 struct cx25821_fh
*fh
= priv
;
242 struct cx25821_dev
*dev
= fh
->dev
;
244 if (unlikely(fh
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
))
249 if (unlikely(i
!= fh
->type
))
254 if (unlikely(!res_get(dev
, fh
, get_resource(fh
, RESOURCE_VIDEO7
))))
259 return videobuf_streamon(get_queue(fh
));
262 static int vidioc_streamoff(struct file
*file
, void *priv
, enum v4l2_buf_type i
)
264 struct cx25821_fh
*fh
= priv
;
265 struct cx25821_dev
*dev
= fh
->dev
;
268 if (fh
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
273 res
= get_resource(fh
, RESOURCE_VIDEO7
);
274 err
= videobuf_streamoff(get_queue(fh
));
277 res_free(dev
, fh
, res
);
282 static int vidioc_s_fmt_vid_cap(struct file
*file
, void *priv
, struct v4l2_format
*f
)
284 struct cx25821_fh
*fh
= priv
;
285 struct cx25821_dev
*dev
= ((struct cx25821_fh
*)priv
)->dev
;
291 err
= v4l2_prio_check(&dev
->prio
, &fh
->prio
);
296 dprintk(2, "%s()\n", __func__
);
297 err
= vidioc_try_fmt_vid_cap(file
, priv
, f
);
302 fh
->fmt
= format_by_fourcc(f
->fmt
.pix
.pixelformat
);
303 fh
->vidq
.field
= f
->fmt
.pix
.field
;
305 // check if width and height is valid based on set standard
306 if (is_valid_width(f
->fmt
.pix
.width
, dev
->tvnorm
))
308 fh
->width
= f
->fmt
.pix
.width
;
311 if (is_valid_height(f
->fmt
.pix
.height
, dev
->tvnorm
))
313 fh
->height
= f
->fmt
.pix
.height
;
316 if (f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_Y41P
)
317 pix_format
= PIXEL_FRMT_411
;
318 else if (f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_YUYV
)
319 pix_format
= PIXEL_FRMT_422
;
323 cx25821_set_pixel_format( dev
, SRAM_CH07
, pix_format
);
325 // check if cif resolution
326 if (fh
->width
== 320 || fh
->width
== 352)
328 dev
->use_cif_resolution
[SRAM_CH07
] = 1;
331 dev
->use_cif_resolution
[SRAM_CH07
] = 0;
333 dev
->cif_width
[SRAM_CH07
] = fh
->width
;
334 medusa_set_resolution( dev
, fh
->width
, SRAM_CH07
);
336 dprintk(2, "%s() width=%d height=%d field=%d\n", __func__
, fh
->width
, fh
->height
, fh
->vidq
.field
);
337 cx25821_call_all(dev
, video
, s_fmt
, f
);
342 static int vidioc_dqbuf(struct file
*file
, void *priv
, struct v4l2_buffer
*p
)
345 struct cx25821_fh
*fh
= priv
;
346 struct cx25821_dev
*dev
= ((struct cx25821_fh
*)priv
)->dev
;
348 ret_val
= videobuf_dqbuf(get_queue(fh
), p
, file
->f_flags
& O_NONBLOCK
);
350 p
->sequence
= dev
->vidq
[SRAM_CH07
].count
;
354 static int vidioc_log_status (struct file
*file
, void *priv
)
356 struct cx25821_dev
*dev
= ((struct cx25821_fh
*)priv
)->dev
;
359 struct sram_channel
*sram_ch
= &dev
->sram_channels
[SRAM_CH07
];
362 snprintf(name
, sizeof(name
), "%s/2", dev
->name
);
363 printk(KERN_INFO
"%s/2: ============ START LOG STATUS ============\n",
365 cx25821_call_all(dev
, core
, log_status
);
367 tmp
= cx_read(sram_ch
->dma_ctl
);
368 printk(KERN_INFO
"Video input 7 is %s\n", (tmp
& 0x11)?"streaming" : "stopped");
369 printk(KERN_INFO
"%s/2: ============= END LOG STATUS =============\n",
374 static int vidioc_s_ctrl(struct file
*file
, void *priv
,
375 struct v4l2_control
*ctl
)
377 struct cx25821_fh
*fh
= priv
;
378 struct cx25821_dev
*dev
= ((struct cx25821_fh
*)priv
)->dev
;
382 err
= v4l2_prio_check(&dev
->prio
, &fh
->prio
);
387 return cx25821_set_control(dev
, ctl
, SRAM_CH07
);
391 static const struct v4l2_file_operations video_fops
= {
392 .owner
= THIS_MODULE
,
394 .release
= video_release
,
398 .ioctl
= video_ioctl2
,
401 static const struct v4l2_ioctl_ops video_ioctl_ops
= {
402 .vidioc_querycap
= vidioc_querycap
,
403 .vidioc_enum_fmt_vid_cap
= vidioc_enum_fmt_vid_cap
,
404 .vidioc_g_fmt_vid_cap
= vidioc_g_fmt_vid_cap
,
405 .vidioc_try_fmt_vid_cap
= vidioc_try_fmt_vid_cap
,
406 .vidioc_s_fmt_vid_cap
= vidioc_s_fmt_vid_cap
,
407 .vidioc_reqbufs
= vidioc_reqbufs
,
408 .vidioc_querybuf
= vidioc_querybuf
,
409 .vidioc_qbuf
= vidioc_qbuf
,
410 .vidioc_dqbuf
= vidioc_dqbuf
,
412 .vidioc_s_std
= vidioc_s_std
,
413 .vidioc_querystd
= vidioc_querystd
,
415 .vidioc_cropcap
= vidioc_cropcap
,
416 .vidioc_s_crop
= vidioc_s_crop
,
417 .vidioc_g_crop
= vidioc_g_crop
,
418 .vidioc_enum_input
= vidioc_enum_input
,
419 .vidioc_g_input
= vidioc_g_input
,
420 .vidioc_s_input
= vidioc_s_input
,
421 .vidioc_g_ctrl
= vidioc_g_ctrl
,
422 .vidioc_s_ctrl
= vidioc_s_ctrl
,
423 .vidioc_queryctrl
= vidioc_queryctrl
,
424 .vidioc_streamon
= vidioc_streamon
,
425 .vidioc_streamoff
= vidioc_streamoff
,
426 .vidioc_log_status
= vidioc_log_status
,
427 .vidioc_g_priority
= vidioc_g_priority
,
428 .vidioc_s_priority
= vidioc_s_priority
,
429 #ifdef CONFIG_VIDEO_V4L1_COMPAT
430 .vidiocgmbuf
= vidiocgmbuf
,
433 .vidioc_g_tuner
= vidioc_g_tuner
,
434 .vidioc_s_tuner
= vidioc_s_tuner
,
435 .vidioc_g_frequency
= vidioc_g_frequency
,
436 .vidioc_s_frequency
= vidioc_s_frequency
,
438 #ifdef CONFIG_VIDEO_ADV_DEBUG
439 .vidioc_g_register
= vidioc_g_register
,
440 .vidioc_s_register
= vidioc_s_register
,
444 struct video_device cx25821_video_template7
= {
445 .name
= "cx25821-video",
448 .ioctl_ops
= &video_ioctl_ops
,
449 .tvnorms
= CX25821_NORMS
,
450 .current_norm
= V4L2_STD_NTSC_M
,