2 * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
5 * Ben Collins <bcollins@ubuntu.com>
8 * John Brooks <john.brooks@bluecherry.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/kthread.h>
28 #include <linux/freezer.h>
30 #include <media/v4l2-ioctl.h>
31 #include <media/v4l2-common.h>
32 #include <media/videobuf-dma-contig.h>
37 #define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED
39 /* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */
40 #define SOLO_HW_BPL 2048
41 #define solo_vlines(__solo) (__solo->video_vsize * 2)
42 #define solo_image_size(__solo) (solo_bytesperline(__solo) * \
44 #define solo_bytesperline(__solo) (__solo->video_hsize * 2)
46 #define MIN_VID_BUFFERS 2
48 /* Simple file handle */
49 struct solo_filehandle
{
50 struct solo_dev
*solo_dev
;
51 struct videobuf_queue vidq
;
52 struct task_struct
*kthread
;
55 struct list_head vidq_active
;
58 static inline void erase_on(struct solo_dev
*solo_dev
)
60 solo_reg_write(solo_dev
, SOLO_VO_DISP_ERASE
, SOLO_VO_DISP_ERASE_ON
);
61 solo_dev
->erasing
= 1;
62 solo_dev
->frame_blank
= 0;
65 static inline int erase_off(struct solo_dev
*solo_dev
)
67 if (!solo_dev
->erasing
)
70 /* First time around, assert erase off */
71 if (!solo_dev
->frame_blank
)
72 solo_reg_write(solo_dev
, SOLO_VO_DISP_ERASE
, 0);
73 /* Keep the erasing flag on for 8 frames minimum */
74 if (solo_dev
->frame_blank
++ >= 8)
75 solo_dev
->erasing
= 0;
80 void solo_video_in_isr(struct solo_dev
*solo_dev
)
82 wake_up_interruptible_all(&solo_dev
->disp_thread_wait
);
85 static void solo_win_setup(struct solo_dev
*solo_dev
, u8 ch
,
86 int sx
, int sy
, int ex
, int ey
, int scale
)
88 if (ch
>= solo_dev
->nr_chans
)
91 /* Here, we just keep window/channel the same */
92 solo_reg_write(solo_dev
, SOLO_VI_WIN_CTRL0(ch
),
93 SOLO_VI_WIN_CHANNEL(ch
) |
96 SOLO_VI_WIN_SCALE(scale
));
98 solo_reg_write(solo_dev
, SOLO_VI_WIN_CTRL1(ch
),
103 static int solo_v4l2_ch_ext_4up(struct solo_dev
*solo_dev
, u8 idx
, int on
)
107 if (ch
>= solo_dev
->nr_chans
)
112 for (i
= ch
; i
< ch
+ 4; i
++)
113 solo_win_setup(solo_dev
, i
, solo_dev
->video_hsize
,
114 solo_vlines(solo_dev
),
115 solo_dev
->video_hsize
,
116 solo_vlines(solo_dev
), 0);
121 solo_win_setup(solo_dev
, ch
, 0, 0, solo_dev
->video_hsize
/ 2,
122 solo_vlines(solo_dev
) / 2, 3);
123 solo_win_setup(solo_dev
, ch
+ 1, solo_dev
->video_hsize
/ 2, 0,
124 solo_dev
->video_hsize
, solo_vlines(solo_dev
) / 2, 3);
126 solo_win_setup(solo_dev
, ch
+ 2, 0, solo_vlines(solo_dev
) / 2,
127 solo_dev
->video_hsize
/ 2, solo_vlines(solo_dev
), 3);
128 solo_win_setup(solo_dev
, ch
+ 3, solo_dev
->video_hsize
/ 2,
129 solo_vlines(solo_dev
) / 2, solo_dev
->video_hsize
,
130 solo_vlines(solo_dev
), 3);
135 static int solo_v4l2_ch_ext_16up(struct solo_dev
*solo_dev
, int on
)
137 int sy
, ysize
, hsize
, i
;
140 for (i
= 0; i
< 16; i
++)
141 solo_win_setup(solo_dev
, i
, solo_dev
->video_hsize
,
142 solo_vlines(solo_dev
),
143 solo_dev
->video_hsize
,
144 solo_vlines(solo_dev
), 0);
148 ysize
= solo_vlines(solo_dev
) / 4;
149 hsize
= solo_dev
->video_hsize
/ 4;
151 for (sy
= 0, i
= 0; i
< 4; i
++, sy
+= ysize
) {
152 solo_win_setup(solo_dev
, i
* 4, 0, sy
, hsize
,
154 solo_win_setup(solo_dev
, (i
* 4) + 1, hsize
, sy
,
155 hsize
* 2, sy
+ ysize
, 5);
156 solo_win_setup(solo_dev
, (i
* 4) + 2, hsize
* 2, sy
,
157 hsize
* 3, sy
+ ysize
, 5);
158 solo_win_setup(solo_dev
, (i
* 4) + 3, hsize
* 3, sy
,
159 solo_dev
->video_hsize
, sy
+ ysize
, 5);
165 static int solo_v4l2_ch(struct solo_dev
*solo_dev
, u8 ch
, int on
)
169 if (ch
< solo_dev
->nr_chans
) {
170 solo_win_setup(solo_dev
, ch
, on
? 0 : solo_dev
->video_hsize
,
171 on
? 0 : solo_vlines(solo_dev
),
172 solo_dev
->video_hsize
, solo_vlines(solo_dev
),
177 if (ch
>= solo_dev
->nr_chans
+ solo_dev
->nr_ext
)
180 ext_ch
= ch
- solo_dev
->nr_chans
;
184 return solo_v4l2_ch_ext_4up(solo_dev
, ext_ch
, on
);
186 /* Remaining case is 16up for 16-port */
187 return solo_v4l2_ch_ext_16up(solo_dev
, on
);
190 static int solo_v4l2_set_ch(struct solo_dev
*solo_dev
, u8 ch
)
192 if (ch
>= solo_dev
->nr_chans
+ solo_dev
->nr_ext
)
197 solo_v4l2_ch(solo_dev
, solo_dev
->cur_disp_ch
, 0);
198 solo_v4l2_ch(solo_dev
, ch
, 1);
200 solo_dev
->cur_disp_ch
= ch
;
205 static void solo_fillbuf(struct solo_filehandle
*fh
,
206 struct videobuf_buffer
*vb
)
208 struct solo_dev
*solo_dev
= fh
->solo_dev
;
210 unsigned int fdma_addr
;
214 vbuf
= videobuf_to_dma_contig(vb
);
218 if (erase_off(solo_dev
)) {
219 void *p
= videobuf_queue_to_vaddr(&fh
->vidq
, vb
);
220 int image_size
= solo_image_size(solo_dev
);
221 for (i
= 0; i
< image_size
; i
+= 2) {
223 ((u8
*)p
)[i
+ 1] = 0x00;
227 fdma_addr
= SOLO_DISP_EXT_ADDR
+ (fh
->old_write
*
228 (SOLO_HW_BPL
* solo_vlines(solo_dev
)));
230 error
= solo_p2m_dma_t(solo_dev
, 0, vbuf
, fdma_addr
,
231 solo_bytesperline(solo_dev
),
232 solo_vlines(solo_dev
), SOLO_HW_BPL
);
237 vb
->state
= VIDEOBUF_ERROR
;
239 vb
->state
= VIDEOBUF_DONE
;
246 static void solo_thread_try(struct solo_filehandle
*fh
)
248 struct videobuf_buffer
*vb
;
250 /* Only "break" from this loop if slock is held, otherwise
253 unsigned int cur_write
;
255 cur_write
= SOLO_VI_STATUS0_PAGE(
256 solo_reg_read(fh
->solo_dev
, SOLO_VI_STATUS0
));
257 if (cur_write
== fh
->old_write
)
260 spin_lock(&fh
->slock
);
262 if (list_empty(&fh
->vidq_active
))
265 vb
= list_first_entry(&fh
->vidq_active
, struct videobuf_buffer
,
268 if (!waitqueue_active(&vb
->done
))
271 fh
->old_write
= cur_write
;
272 list_del(&vb
->queue
);
273 vb
->state
= VIDEOBUF_ACTIVE
;
275 spin_unlock(&fh
->slock
);
277 solo_fillbuf(fh
, vb
);
280 assert_spin_locked(&fh
->slock
);
281 spin_unlock(&fh
->slock
);
284 static int solo_thread(void *data
)
286 struct solo_filehandle
*fh
= data
;
287 struct solo_dev
*solo_dev
= fh
->solo_dev
;
288 DECLARE_WAITQUEUE(wait
, current
);
291 add_wait_queue(&solo_dev
->disp_thread_wait
, &wait
);
294 long timeout
= schedule_timeout_interruptible(HZ
);
295 if (timeout
== -ERESTARTSYS
|| kthread_should_stop())
301 remove_wait_queue(&solo_dev
->disp_thread_wait
, &wait
);
306 static int solo_start_thread(struct solo_filehandle
*fh
)
310 if (atomic_inc_return(&fh
->solo_dev
->disp_users
) == 1)
311 solo_irq_on(fh
->solo_dev
, SOLO_IRQ_VIDEO_IN
);
313 fh
->kthread
= kthread_run(solo_thread
, fh
, SOLO6X10_NAME
"_disp");
315 if (IS_ERR(fh
->kthread
)) {
316 ret
= PTR_ERR(fh
->kthread
);
323 static void solo_stop_thread(struct solo_filehandle
*fh
)
328 kthread_stop(fh
->kthread
);
331 if (atomic_dec_return(&fh
->solo_dev
->disp_users
) == 0)
332 solo_irq_off(fh
->solo_dev
, SOLO_IRQ_VIDEO_IN
);
335 static int solo_buf_setup(struct videobuf_queue
*vq
, unsigned int *count
,
338 struct solo_filehandle
*fh
= vq
->priv_data
;
339 struct solo_dev
*solo_dev
= fh
->solo_dev
;
341 *size
= solo_image_size(solo_dev
);
343 if (*count
< MIN_VID_BUFFERS
)
344 *count
= MIN_VID_BUFFERS
;
349 static int solo_buf_prepare(struct videobuf_queue
*vq
,
350 struct videobuf_buffer
*vb
, enum v4l2_field field
)
352 struct solo_filehandle
*fh
= vq
->priv_data
;
353 struct solo_dev
*solo_dev
= fh
->solo_dev
;
355 vb
->size
= solo_image_size(solo_dev
);
356 if (vb
->baddr
!= 0 && vb
->bsize
< vb
->size
)
359 /* XXX: These properties only change when queue is idle */
360 vb
->width
= solo_dev
->video_hsize
;
361 vb
->height
= solo_vlines(solo_dev
);
362 vb
->bytesperline
= solo_bytesperline(solo_dev
);
365 if (vb
->state
== VIDEOBUF_NEEDS_INIT
) {
366 int rc
= videobuf_iolock(vq
, vb
, NULL
);
368 videobuf_dma_contig_free(vq
, vb
);
369 vb
->state
= VIDEOBUF_NEEDS_INIT
;
373 vb
->state
= VIDEOBUF_PREPARED
;
378 static void solo_buf_queue(struct videobuf_queue
*vq
,
379 struct videobuf_buffer
*vb
)
381 struct solo_filehandle
*fh
= vq
->priv_data
;
382 struct solo_dev
*solo_dev
= fh
->solo_dev
;
384 vb
->state
= VIDEOBUF_QUEUED
;
385 list_add_tail(&vb
->queue
, &fh
->vidq_active
);
386 wake_up_interruptible(&solo_dev
->disp_thread_wait
);
389 static void solo_buf_release(struct videobuf_queue
*vq
,
390 struct videobuf_buffer
*vb
)
392 videobuf_dma_contig_free(vq
, vb
);
393 vb
->state
= VIDEOBUF_NEEDS_INIT
;
396 static const struct videobuf_queue_ops solo_video_qops
= {
397 .buf_setup
= solo_buf_setup
,
398 .buf_prepare
= solo_buf_prepare
,
399 .buf_queue
= solo_buf_queue
,
400 .buf_release
= solo_buf_release
,
403 static unsigned int solo_v4l2_poll(struct file
*file
,
404 struct poll_table_struct
*wait
)
406 struct solo_filehandle
*fh
= file
->private_data
;
408 return videobuf_poll_stream(file
, &fh
->vidq
, wait
);
411 static int solo_v4l2_mmap(struct file
*file
, struct vm_area_struct
*vma
)
413 struct solo_filehandle
*fh
= file
->private_data
;
415 return videobuf_mmap_mapper(&fh
->vidq
, vma
);
418 static int solo_v4l2_open(struct file
*file
)
420 struct solo_dev
*solo_dev
= video_drvdata(file
);
421 struct solo_filehandle
*fh
;
424 fh
= kzalloc(sizeof(*fh
), GFP_KERNEL
);
428 spin_lock_init(&fh
->slock
);
429 INIT_LIST_HEAD(&fh
->vidq_active
);
430 fh
->solo_dev
= solo_dev
;
431 file
->private_data
= fh
;
433 ret
= solo_start_thread(fh
);
439 videobuf_queue_dma_contig_init(&fh
->vidq
, &solo_video_qops
,
440 &solo_dev
->pdev
->dev
, &fh
->slock
,
441 V4L2_BUF_TYPE_VIDEO_CAPTURE
,
443 sizeof(struct videobuf_buffer
),
448 static ssize_t
solo_v4l2_read(struct file
*file
, char __user
*data
,
449 size_t count
, loff_t
*ppos
)
451 struct solo_filehandle
*fh
= file
->private_data
;
453 return videobuf_read_stream(&fh
->vidq
, data
, count
, ppos
, 0,
454 file
->f_flags
& O_NONBLOCK
);
457 static int solo_v4l2_release(struct file
*file
)
459 struct solo_filehandle
*fh
= file
->private_data
;
461 solo_stop_thread(fh
);
463 videobuf_stop(&fh
->vidq
);
464 videobuf_mmap_free(&fh
->vidq
);
471 static int solo_querycap(struct file
*file
, void *priv
,
472 struct v4l2_capability
*cap
)
474 struct solo_filehandle
*fh
= priv
;
475 struct solo_dev
*solo_dev
= fh
->solo_dev
;
477 strcpy(cap
->driver
, SOLO6X10_NAME
);
478 strcpy(cap
->card
, "Softlogic 6x10");
479 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
), "PCI %s",
480 pci_name(solo_dev
->pdev
));
481 cap
->version
= SOLO6X10_VER_NUM
;
482 cap
->capabilities
= V4L2_CAP_VIDEO_CAPTURE
|
488 static int solo_enum_ext_input(struct solo_dev
*solo_dev
,
489 struct v4l2_input
*input
)
491 static const char * const dispnames_1
[] = { "4UP" };
492 static const char * const dispnames_2
[] = { "4UP-1", "4UP-2" };
493 static const char * const dispnames_5
[] = {
494 "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
496 const char * const *dispnames
;
498 if (input
->index
>= (solo_dev
->nr_chans
+ solo_dev
->nr_ext
))
501 if (solo_dev
->nr_ext
== 5)
502 dispnames
= dispnames_5
;
503 else if (solo_dev
->nr_ext
== 2)
504 dispnames
= dispnames_2
;
506 dispnames
= dispnames_1
;
508 snprintf(input
->name
, sizeof(input
->name
), "Multi %s",
509 dispnames
[input
->index
- solo_dev
->nr_chans
]);
514 static int solo_enum_input(struct file
*file
, void *priv
,
515 struct v4l2_input
*input
)
517 struct solo_filehandle
*fh
= priv
;
518 struct solo_dev
*solo_dev
= fh
->solo_dev
;
520 if (input
->index
>= solo_dev
->nr_chans
) {
521 int ret
= solo_enum_ext_input(solo_dev
, input
);
525 snprintf(input
->name
, sizeof(input
->name
), "Camera %d",
528 /* We can only check this for normal inputs */
529 if (!tw28_get_video_status(solo_dev
, input
->index
))
530 input
->status
= V4L2_IN_ST_NO_SIGNAL
;
533 input
->type
= V4L2_INPUT_TYPE_CAMERA
;
535 if (solo_dev
->video_type
== SOLO_VO_FMT_TYPE_NTSC
)
536 input
->std
= V4L2_STD_NTSC_M
;
538 input
->std
= V4L2_STD_PAL_B
;
543 static int solo_set_input(struct file
*file
, void *priv
, unsigned int index
)
545 struct solo_filehandle
*fh
= priv
;
546 int ret
= solo_v4l2_set_ch(fh
->solo_dev
, index
);
549 while (erase_off(fh
->solo_dev
))
556 static int solo_get_input(struct file
*file
, void *priv
, unsigned int *index
)
558 struct solo_filehandle
*fh
= priv
;
560 *index
= fh
->solo_dev
->cur_disp_ch
;
565 static int solo_enum_fmt_cap(struct file
*file
, void *priv
,
566 struct v4l2_fmtdesc
*f
)
571 f
->pixelformat
= V4L2_PIX_FMT_UYVY
;
572 strlcpy(f
->description
, "UYUV 4:2:2 Packed", sizeof(f
->description
));
577 static int solo_try_fmt_cap(struct file
*file
, void *priv
,
578 struct v4l2_format
*f
)
580 struct solo_filehandle
*fh
= priv
;
581 struct solo_dev
*solo_dev
= fh
->solo_dev
;
582 struct v4l2_pix_format
*pix
= &f
->fmt
.pix
;
583 int image_size
= solo_image_size(solo_dev
);
585 /* Check supported sizes */
586 if (pix
->width
!= solo_dev
->video_hsize
)
587 pix
->width
= solo_dev
->video_hsize
;
588 if (pix
->height
!= solo_vlines(solo_dev
))
589 pix
->height
= solo_vlines(solo_dev
);
590 if (pix
->sizeimage
!= image_size
)
591 pix
->sizeimage
= image_size
;
594 if (pix
->field
== V4L2_FIELD_ANY
)
595 pix
->field
= SOLO_DISP_PIX_FIELD
;
597 if (pix
->pixelformat
!= V4L2_PIX_FMT_UYVY
||
598 pix
->field
!= SOLO_DISP_PIX_FIELD
||
599 pix
->colorspace
!= V4L2_COLORSPACE_SMPTE170M
)
605 static int solo_set_fmt_cap(struct file
*file
, void *priv
,
606 struct v4l2_format
*f
)
608 struct solo_filehandle
*fh
= priv
;
610 if (videobuf_queue_is_busy(&fh
->vidq
))
613 /* For right now, if it doesn't match our running config,
615 return solo_try_fmt_cap(file
, priv
, f
);
618 static int solo_get_fmt_cap(struct file
*file
, void *priv
,
619 struct v4l2_format
*f
)
621 struct solo_filehandle
*fh
= priv
;
622 struct solo_dev
*solo_dev
= fh
->solo_dev
;
623 struct v4l2_pix_format
*pix
= &f
->fmt
.pix
;
625 pix
->width
= solo_dev
->video_hsize
;
626 pix
->height
= solo_vlines(solo_dev
);
627 pix
->pixelformat
= V4L2_PIX_FMT_UYVY
;
628 pix
->field
= SOLO_DISP_PIX_FIELD
;
629 pix
->sizeimage
= solo_image_size(solo_dev
);
630 pix
->colorspace
= V4L2_COLORSPACE_SMPTE170M
;
631 pix
->bytesperline
= solo_bytesperline(solo_dev
);
636 static int solo_reqbufs(struct file
*file
, void *priv
,
637 struct v4l2_requestbuffers
*req
)
639 struct solo_filehandle
*fh
= priv
;
641 return videobuf_reqbufs(&fh
->vidq
, req
);
644 static int solo_querybuf(struct file
*file
, void *priv
,
645 struct v4l2_buffer
*buf
)
647 struct solo_filehandle
*fh
= priv
;
649 return videobuf_querybuf(&fh
->vidq
, buf
);
652 static int solo_qbuf(struct file
*file
, void *priv
, struct v4l2_buffer
*buf
)
654 struct solo_filehandle
*fh
= priv
;
656 return videobuf_qbuf(&fh
->vidq
, buf
);
659 static int solo_dqbuf(struct file
*file
, void *priv
, struct v4l2_buffer
*buf
)
661 struct solo_filehandle
*fh
= priv
;
663 return videobuf_dqbuf(&fh
->vidq
, buf
, file
->f_flags
& O_NONBLOCK
);
666 static int solo_streamon(struct file
*file
, void *priv
, enum v4l2_buf_type i
)
668 struct solo_filehandle
*fh
= priv
;
670 if (i
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
673 return videobuf_streamon(&fh
->vidq
);
676 static int solo_streamoff(struct file
*file
, void *priv
, enum v4l2_buf_type i
)
678 struct solo_filehandle
*fh
= priv
;
680 if (i
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
683 return videobuf_streamoff(&fh
->vidq
);
686 static int solo_s_std(struct file
*file
, void *priv
, v4l2_std_id i
)
691 static const u32 solo_motion_ctrls
[] = {
692 V4L2_CID_MOTION_TRACE
,
696 static const u32
*solo_ctrl_classes
[] = {
701 static int solo_disp_queryctrl(struct file
*file
, void *priv
,
702 struct v4l2_queryctrl
*qc
)
704 qc
->id
= v4l2_ctrl_next(solo_ctrl_classes
, qc
->id
);
710 case V4L2_CID_MOTION_TRACE
:
711 qc
->type
= V4L2_CTRL_TYPE_BOOLEAN
;
713 qc
->maximum
= qc
->step
= 1;
714 qc
->default_value
= 0;
715 strlcpy(qc
->name
, "Motion Detection Trace", sizeof(qc
->name
));
718 case V4L2_CID_MOTION_TRACE
:
719 return v4l2_ctrl_query_fill(qc
, 0, 1, 1, 0);
725 static int solo_disp_g_ctrl(struct file
*file
, void *priv
,
726 struct v4l2_control
*ctrl
)
728 struct solo_filehandle
*fh
= priv
;
729 struct solo_dev
*solo_dev
= fh
->solo_dev
;
732 case V4L2_CID_MOTION_TRACE
:
733 ctrl
->value
= solo_reg_read(solo_dev
, SOLO_VI_MOTION_BAR
)
740 static int solo_disp_s_ctrl(struct file
*file
, void *priv
,
741 struct v4l2_control
*ctrl
)
743 struct solo_filehandle
*fh
= priv
;
744 struct solo_dev
*solo_dev
= fh
->solo_dev
;
747 case V4L2_CID_MOTION_TRACE
:
749 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BORDER
,
750 SOLO_VI_MOTION_Y_ADD
|
751 SOLO_VI_MOTION_Y_VALUE(0x20) |
752 SOLO_VI_MOTION_CB_VALUE(0x10) |
753 SOLO_VI_MOTION_CR_VALUE(0x10));
754 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BAR
,
755 SOLO_VI_MOTION_CR_ADD
|
756 SOLO_VI_MOTION_Y_VALUE(0x10) |
757 SOLO_VI_MOTION_CB_VALUE(0x80) |
758 SOLO_VI_MOTION_CR_VALUE(0x10));
760 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BORDER
, 0);
761 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BAR
, 0);
768 static const struct v4l2_file_operations solo_v4l2_fops
= {
769 .owner
= THIS_MODULE
,
770 .open
= solo_v4l2_open
,
771 .release
= solo_v4l2_release
,
772 .read
= solo_v4l2_read
,
773 .poll
= solo_v4l2_poll
,
774 .mmap
= solo_v4l2_mmap
,
775 .ioctl
= video_ioctl2
,
778 static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops
= {
779 .vidioc_querycap
= solo_querycap
,
780 .vidioc_s_std
= solo_s_std
,
781 /* Input callbacks */
782 .vidioc_enum_input
= solo_enum_input
,
783 .vidioc_s_input
= solo_set_input
,
784 .vidioc_g_input
= solo_get_input
,
785 /* Video capture format callbacks */
786 .vidioc_enum_fmt_vid_cap
= solo_enum_fmt_cap
,
787 .vidioc_try_fmt_vid_cap
= solo_try_fmt_cap
,
788 .vidioc_s_fmt_vid_cap
= solo_set_fmt_cap
,
789 .vidioc_g_fmt_vid_cap
= solo_get_fmt_cap
,
791 .vidioc_reqbufs
= solo_reqbufs
,
792 .vidioc_querybuf
= solo_querybuf
,
793 .vidioc_qbuf
= solo_qbuf
,
794 .vidioc_dqbuf
= solo_dqbuf
,
795 .vidioc_streamon
= solo_streamon
,
796 .vidioc_streamoff
= solo_streamoff
,
798 .vidioc_queryctrl
= solo_disp_queryctrl
,
799 .vidioc_g_ctrl
= solo_disp_g_ctrl
,
800 .vidioc_s_ctrl
= solo_disp_s_ctrl
,
803 static struct video_device solo_v4l2_template
= {
804 .name
= SOLO6X10_NAME
,
805 .fops
= &solo_v4l2_fops
,
806 .ioctl_ops
= &solo_v4l2_ioctl_ops
,
808 .release
= video_device_release
,
810 .tvnorms
= V4L2_STD_NTSC_M
| V4L2_STD_PAL_B
,
811 .current_norm
= V4L2_STD_NTSC_M
,
814 int solo_v4l2_init(struct solo_dev
*solo_dev
, unsigned nr
)
819 atomic_set(&solo_dev
->disp_users
, 0);
820 init_waitqueue_head(&solo_dev
->disp_thread_wait
);
822 solo_dev
->vfd
= video_device_alloc();
826 *solo_dev
->vfd
= solo_v4l2_template
;
827 solo_dev
->vfd
->parent
= &solo_dev
->pdev
->dev
;
829 ret
= video_register_device(solo_dev
->vfd
, VFL_TYPE_GRABBER
, nr
);
831 video_device_release(solo_dev
->vfd
);
832 solo_dev
->vfd
= NULL
;
836 video_set_drvdata(solo_dev
->vfd
, solo_dev
);
838 snprintf(solo_dev
->vfd
->name
, sizeof(solo_dev
->vfd
->name
), "%s (%i)",
839 SOLO6X10_NAME
, solo_dev
->vfd
->num
);
841 dev_info(&solo_dev
->pdev
->dev
,
842 "Display as /dev/video%d with %d inputs (%d extended)\n",
843 solo_dev
->vfd
->num
, solo_dev
->nr_chans
, solo_dev
->nr_ext
);
845 /* Cycle all the channels and clear */
846 for (i
= 0; i
< solo_dev
->nr_chans
; i
++) {
847 solo_v4l2_set_ch(solo_dev
, i
);
848 while (erase_off(solo_dev
))
852 /* Set the default display channel */
853 solo_v4l2_set_ch(solo_dev
, 0);
854 while (erase_off(solo_dev
))
860 void solo_v4l2_exit(struct solo_dev
*solo_dev
)
862 if (solo_dev
->vfd
== NULL
)
865 video_unregister_device(solo_dev
->vfd
);
866 solo_dev
->vfd
= NULL
;