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/v4l2-event.h>
33 #include <media/videobuf-dma-contig.h>
38 /* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */
39 #define SOLO_HW_BPL 2048
40 #define solo_vlines(__solo) (__solo->video_vsize * 2)
41 #define solo_image_size(__solo) (solo_bytesperline(__solo) * \
43 #define solo_bytesperline(__solo) (__solo->video_hsize * 2)
45 #define MIN_VID_BUFFERS 2
47 static inline void erase_on(struct solo_dev
*solo_dev
)
49 solo_reg_write(solo_dev
, SOLO_VO_DISP_ERASE
, SOLO_VO_DISP_ERASE_ON
);
50 solo_dev
->erasing
= 1;
51 solo_dev
->frame_blank
= 0;
54 static inline int erase_off(struct solo_dev
*solo_dev
)
56 if (!solo_dev
->erasing
)
59 /* First time around, assert erase off */
60 if (!solo_dev
->frame_blank
)
61 solo_reg_write(solo_dev
, SOLO_VO_DISP_ERASE
, 0);
62 /* Keep the erasing flag on for 8 frames minimum */
63 if (solo_dev
->frame_blank
++ >= 8)
64 solo_dev
->erasing
= 0;
69 void solo_video_in_isr(struct solo_dev
*solo_dev
)
71 wake_up_interruptible_all(&solo_dev
->disp_thread_wait
);
74 static void solo_win_setup(struct solo_dev
*solo_dev
, u8 ch
,
75 int sx
, int sy
, int ex
, int ey
, int scale
)
77 if (ch
>= solo_dev
->nr_chans
)
80 /* Here, we just keep window/channel the same */
81 solo_reg_write(solo_dev
, SOLO_VI_WIN_CTRL0(ch
),
82 SOLO_VI_WIN_CHANNEL(ch
) |
85 SOLO_VI_WIN_SCALE(scale
));
87 solo_reg_write(solo_dev
, SOLO_VI_WIN_CTRL1(ch
),
92 static int solo_v4l2_ch_ext_4up(struct solo_dev
*solo_dev
, u8 idx
, int on
)
96 if (ch
>= solo_dev
->nr_chans
)
101 for (i
= ch
; i
< ch
+ 4; i
++)
102 solo_win_setup(solo_dev
, i
, solo_dev
->video_hsize
,
103 solo_vlines(solo_dev
),
104 solo_dev
->video_hsize
,
105 solo_vlines(solo_dev
), 0);
110 solo_win_setup(solo_dev
, ch
, 0, 0, solo_dev
->video_hsize
/ 2,
111 solo_vlines(solo_dev
) / 2, 3);
112 solo_win_setup(solo_dev
, ch
+ 1, solo_dev
->video_hsize
/ 2, 0,
113 solo_dev
->video_hsize
, solo_vlines(solo_dev
) / 2, 3);
115 solo_win_setup(solo_dev
, ch
+ 2, 0, solo_vlines(solo_dev
) / 2,
116 solo_dev
->video_hsize
/ 2, solo_vlines(solo_dev
), 3);
117 solo_win_setup(solo_dev
, ch
+ 3, solo_dev
->video_hsize
/ 2,
118 solo_vlines(solo_dev
) / 2, solo_dev
->video_hsize
,
119 solo_vlines(solo_dev
), 3);
124 static int solo_v4l2_ch_ext_16up(struct solo_dev
*solo_dev
, int on
)
126 int sy
, ysize
, hsize
, i
;
129 for (i
= 0; i
< 16; i
++)
130 solo_win_setup(solo_dev
, i
, solo_dev
->video_hsize
,
131 solo_vlines(solo_dev
),
132 solo_dev
->video_hsize
,
133 solo_vlines(solo_dev
), 0);
137 ysize
= solo_vlines(solo_dev
) / 4;
138 hsize
= solo_dev
->video_hsize
/ 4;
140 for (sy
= 0, i
= 0; i
< 4; i
++, sy
+= ysize
) {
141 solo_win_setup(solo_dev
, i
* 4, 0, sy
, hsize
,
143 solo_win_setup(solo_dev
, (i
* 4) + 1, hsize
, sy
,
144 hsize
* 2, sy
+ ysize
, 5);
145 solo_win_setup(solo_dev
, (i
* 4) + 2, hsize
* 2, sy
,
146 hsize
* 3, sy
+ ysize
, 5);
147 solo_win_setup(solo_dev
, (i
* 4) + 3, hsize
* 3, sy
,
148 solo_dev
->video_hsize
, sy
+ ysize
, 5);
154 static int solo_v4l2_ch(struct solo_dev
*solo_dev
, u8 ch
, int on
)
158 if (ch
< solo_dev
->nr_chans
) {
159 solo_win_setup(solo_dev
, ch
, on
? 0 : solo_dev
->video_hsize
,
160 on
? 0 : solo_vlines(solo_dev
),
161 solo_dev
->video_hsize
, solo_vlines(solo_dev
),
166 if (ch
>= solo_dev
->nr_chans
+ solo_dev
->nr_ext
)
169 ext_ch
= ch
- solo_dev
->nr_chans
;
173 return solo_v4l2_ch_ext_4up(solo_dev
, ext_ch
, on
);
175 /* Remaining case is 16up for 16-port */
176 return solo_v4l2_ch_ext_16up(solo_dev
, on
);
179 static int solo_v4l2_set_ch(struct solo_dev
*solo_dev
, u8 ch
)
181 if (ch
>= solo_dev
->nr_chans
+ solo_dev
->nr_ext
)
186 solo_v4l2_ch(solo_dev
, solo_dev
->cur_disp_ch
, 0);
187 solo_v4l2_ch(solo_dev
, ch
, 1);
189 solo_dev
->cur_disp_ch
= ch
;
194 static void solo_fillbuf(struct solo_dev
*solo_dev
,
195 struct videobuf_buffer
*vb
)
198 unsigned int fdma_addr
;
202 vbuf
= videobuf_to_dma_contig(vb
);
206 if (erase_off(solo_dev
)) {
207 void *p
= videobuf_queue_to_vaddr(&solo_dev
->vidq
, vb
);
208 int image_size
= solo_image_size(solo_dev
);
209 for (i
= 0; i
< image_size
; i
+= 2) {
211 ((u8
*)p
)[i
+ 1] = 0x00;
215 fdma_addr
= SOLO_DISP_EXT_ADDR
+ (solo_dev
->old_write
*
216 (SOLO_HW_BPL
* solo_vlines(solo_dev
)));
218 error
= solo_p2m_dma_t(solo_dev
, 0, vbuf
, fdma_addr
,
219 solo_bytesperline(solo_dev
),
220 solo_vlines(solo_dev
), SOLO_HW_BPL
);
225 vb
->state
= VIDEOBUF_ERROR
;
227 vb
->state
= VIDEOBUF_DONE
;
234 static void solo_thread_try(struct solo_dev
*solo_dev
)
236 struct videobuf_buffer
*vb
;
238 /* Only "break" from this loop if slock is held, otherwise
241 unsigned int cur_write
;
243 cur_write
= SOLO_VI_STATUS0_PAGE(
244 solo_reg_read(solo_dev
, SOLO_VI_STATUS0
));
245 if (cur_write
== solo_dev
->old_write
)
248 spin_lock(&solo_dev
->slock
);
250 if (list_empty(&solo_dev
->vidq_active
))
253 vb
= list_first_entry(&solo_dev
->vidq_active
, struct videobuf_buffer
,
256 if (!waitqueue_active(&vb
->done
))
259 solo_dev
->old_write
= cur_write
;
260 list_del(&vb
->queue
);
261 vb
->state
= VIDEOBUF_ACTIVE
;
263 spin_unlock(&solo_dev
->slock
);
265 solo_fillbuf(solo_dev
, vb
);
268 assert_spin_locked(&solo_dev
->slock
);
269 spin_unlock(&solo_dev
->slock
);
272 static int solo_thread(void *data
)
274 struct solo_dev
*solo_dev
= data
;
275 DECLARE_WAITQUEUE(wait
, current
);
278 add_wait_queue(&solo_dev
->disp_thread_wait
, &wait
);
281 long timeout
= schedule_timeout_interruptible(HZ
);
282 if (timeout
== -ERESTARTSYS
|| kthread_should_stop())
284 solo_thread_try(solo_dev
);
288 remove_wait_queue(&solo_dev
->disp_thread_wait
, &wait
);
293 static int solo_start_thread(struct solo_dev
*solo_dev
)
297 if (atomic_inc_return(&solo_dev
->disp_users
) == 1)
298 solo_irq_on(solo_dev
, SOLO_IRQ_VIDEO_IN
);
300 solo_dev
->kthread
= kthread_run(solo_thread
, solo_dev
, SOLO6X10_NAME
"_disp");
302 if (IS_ERR(solo_dev
->kthread
)) {
303 ret
= PTR_ERR(solo_dev
->kthread
);
304 solo_dev
->kthread
= NULL
;
310 static void solo_stop_thread(struct solo_dev
*solo_dev
)
312 if (!solo_dev
->kthread
)
315 kthread_stop(solo_dev
->kthread
);
316 solo_dev
->kthread
= NULL
;
318 if (atomic_dec_return(&solo_dev
->disp_users
) == 0)
319 solo_irq_off(solo_dev
, SOLO_IRQ_VIDEO_IN
);
322 static int solo_buf_setup(struct videobuf_queue
*vq
, unsigned int *count
,
325 struct solo_dev
*solo_dev
= vq
->priv_data
;
327 *size
= solo_image_size(solo_dev
);
329 if (*count
< MIN_VID_BUFFERS
)
330 *count
= MIN_VID_BUFFERS
;
335 static int solo_buf_prepare(struct videobuf_queue
*vq
,
336 struct videobuf_buffer
*vb
, enum v4l2_field field
)
338 struct solo_dev
*solo_dev
= vq
->priv_data
;
340 vb
->size
= solo_image_size(solo_dev
);
341 if (vb
->baddr
!= 0 && vb
->bsize
< vb
->size
)
344 /* XXX: These properties only change when queue is idle */
345 vb
->width
= solo_dev
->video_hsize
;
346 vb
->height
= solo_vlines(solo_dev
);
347 vb
->bytesperline
= solo_bytesperline(solo_dev
);
350 if (vb
->state
== VIDEOBUF_NEEDS_INIT
) {
351 int rc
= videobuf_iolock(vq
, vb
, NULL
);
353 videobuf_dma_contig_free(vq
, vb
);
354 vb
->state
= VIDEOBUF_NEEDS_INIT
;
358 vb
->state
= VIDEOBUF_PREPARED
;
363 static void solo_buf_queue(struct videobuf_queue
*vq
,
364 struct videobuf_buffer
*vb
)
366 struct solo_dev
*solo_dev
= vq
->priv_data
;
368 vb
->state
= VIDEOBUF_QUEUED
;
369 list_add_tail(&vb
->queue
, &solo_dev
->vidq_active
);
370 wake_up_interruptible(&solo_dev
->disp_thread_wait
);
373 static void solo_buf_release(struct videobuf_queue
*vq
,
374 struct videobuf_buffer
*vb
)
376 videobuf_dma_contig_free(vq
, vb
);
377 vb
->state
= VIDEOBUF_NEEDS_INIT
;
380 static const struct videobuf_queue_ops solo_video_qops
= {
381 .buf_setup
= solo_buf_setup
,
382 .buf_prepare
= solo_buf_prepare
,
383 .buf_queue
= solo_buf_queue
,
384 .buf_release
= solo_buf_release
,
387 static unsigned int solo_v4l2_poll(struct file
*file
,
388 struct poll_table_struct
*wait
)
390 struct solo_dev
*solo_dev
= video_drvdata(file
);
391 unsigned long req_events
= poll_requested_events(wait
);
392 unsigned res
= v4l2_ctrl_poll(file
, wait
);
394 if (!(req_events
& (POLLIN
| POLLRDNORM
)))
396 return res
| videobuf_poll_stream(file
, &solo_dev
->vidq
, wait
);
399 static int solo_v4l2_mmap(struct file
*file
, struct vm_area_struct
*vma
)
401 struct solo_dev
*solo_dev
= video_drvdata(file
);
403 return videobuf_mmap_mapper(&solo_dev
->vidq
, vma
);
406 static ssize_t
solo_v4l2_read(struct file
*file
, char __user
*data
,
407 size_t count
, loff_t
*ppos
)
409 struct solo_dev
*solo_dev
= video_drvdata(file
);
411 return videobuf_read_stream(&solo_dev
->vidq
, data
, count
, ppos
, 0,
412 file
->f_flags
& O_NONBLOCK
);
415 static int solo_v4l2_release(struct file
*file
)
417 struct solo_dev
*solo_dev
= video_drvdata(file
);
419 solo_stop_thread(solo_dev
);
420 videobuf_stop(&solo_dev
->vidq
);
421 videobuf_mmap_free(&solo_dev
->vidq
);
422 return v4l2_fh_release(file
);
425 static int solo_querycap(struct file
*file
, void *priv
,
426 struct v4l2_capability
*cap
)
428 struct solo_dev
*solo_dev
= video_drvdata(file
);
430 strcpy(cap
->driver
, SOLO6X10_NAME
);
431 strcpy(cap
->card
, "Softlogic 6x10");
432 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
), "PCI:%s",
433 pci_name(solo_dev
->pdev
));
434 cap
->device_caps
= V4L2_CAP_VIDEO_CAPTURE
|
435 V4L2_CAP_READWRITE
| V4L2_CAP_STREAMING
;
436 cap
->capabilities
= cap
->device_caps
| V4L2_CAP_DEVICE_CAPS
;
440 static int solo_enum_ext_input(struct solo_dev
*solo_dev
,
441 struct v4l2_input
*input
)
443 static const char * const dispnames_1
[] = { "4UP" };
444 static const char * const dispnames_2
[] = { "4UP-1", "4UP-2" };
445 static const char * const dispnames_5
[] = {
446 "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
448 const char * const *dispnames
;
450 if (input
->index
>= (solo_dev
->nr_chans
+ solo_dev
->nr_ext
))
453 if (solo_dev
->nr_ext
== 5)
454 dispnames
= dispnames_5
;
455 else if (solo_dev
->nr_ext
== 2)
456 dispnames
= dispnames_2
;
458 dispnames
= dispnames_1
;
460 snprintf(input
->name
, sizeof(input
->name
), "Multi %s",
461 dispnames
[input
->index
- solo_dev
->nr_chans
]);
466 static int solo_enum_input(struct file
*file
, void *priv
,
467 struct v4l2_input
*input
)
469 struct solo_dev
*solo_dev
= video_drvdata(file
);
471 if (input
->index
>= solo_dev
->nr_chans
) {
472 int ret
= solo_enum_ext_input(solo_dev
, input
);
476 snprintf(input
->name
, sizeof(input
->name
), "Camera %d",
479 /* We can only check this for normal inputs */
480 if (!tw28_get_video_status(solo_dev
, input
->index
))
481 input
->status
= V4L2_IN_ST_NO_SIGNAL
;
484 input
->type
= V4L2_INPUT_TYPE_CAMERA
;
486 if (solo_dev
->video_type
== SOLO_VO_FMT_TYPE_NTSC
)
487 input
->std
= V4L2_STD_NTSC_M
;
489 input
->std
= V4L2_STD_PAL_B
;
494 static int solo_set_input(struct file
*file
, void *priv
, unsigned int index
)
496 struct solo_dev
*solo_dev
= video_drvdata(file
);
497 int ret
= solo_v4l2_set_ch(solo_dev
, index
);
500 while (erase_off(solo_dev
))
507 static int solo_get_input(struct file
*file
, void *priv
, unsigned int *index
)
509 struct solo_dev
*solo_dev
= video_drvdata(file
);
511 *index
= solo_dev
->cur_disp_ch
;
516 static int solo_enum_fmt_cap(struct file
*file
, void *priv
,
517 struct v4l2_fmtdesc
*f
)
522 f
->pixelformat
= V4L2_PIX_FMT_UYVY
;
523 strlcpy(f
->description
, "UYUV 4:2:2 Packed", sizeof(f
->description
));
528 static int solo_try_fmt_cap(struct file
*file
, void *priv
,
529 struct v4l2_format
*f
)
531 struct solo_dev
*solo_dev
= video_drvdata(file
);
532 struct v4l2_pix_format
*pix
= &f
->fmt
.pix
;
533 int image_size
= solo_image_size(solo_dev
);
535 if (pix
->pixelformat
!= V4L2_PIX_FMT_UYVY
)
538 pix
->width
= solo_dev
->video_hsize
;
539 pix
->height
= solo_vlines(solo_dev
);
540 pix
->sizeimage
= image_size
;
541 pix
->field
= V4L2_FIELD_INTERLACED
;
542 pix
->pixelformat
= V4L2_PIX_FMT_UYVY
;
543 pix
->colorspace
= V4L2_COLORSPACE_SMPTE170M
;
548 static int solo_set_fmt_cap(struct file
*file
, void *priv
,
549 struct v4l2_format
*f
)
551 struct solo_dev
*solo_dev
= video_drvdata(file
);
553 if (videobuf_queue_is_busy(&solo_dev
->vidq
))
556 /* For right now, if it doesn't match our running config,
558 return solo_try_fmt_cap(file
, priv
, f
);
561 static int solo_get_fmt_cap(struct file
*file
, void *priv
,
562 struct v4l2_format
*f
)
564 struct solo_dev
*solo_dev
= video_drvdata(file
);
565 struct v4l2_pix_format
*pix
= &f
->fmt
.pix
;
567 pix
->width
= solo_dev
->video_hsize
;
568 pix
->height
= solo_vlines(solo_dev
);
569 pix
->pixelformat
= V4L2_PIX_FMT_UYVY
;
570 pix
->field
= V4L2_FIELD_INTERLACED
;
571 pix
->sizeimage
= solo_image_size(solo_dev
);
572 pix
->colorspace
= V4L2_COLORSPACE_SMPTE170M
;
573 pix
->bytesperline
= solo_bytesperline(solo_dev
);
579 static int solo_reqbufs(struct file
*file
, void *priv
,
580 struct v4l2_requestbuffers
*req
)
582 struct solo_dev
*solo_dev
= video_drvdata(file
);
584 return videobuf_reqbufs(&solo_dev
->vidq
, req
);
587 static int solo_querybuf(struct file
*file
, void *priv
,
588 struct v4l2_buffer
*buf
)
590 struct solo_dev
*solo_dev
= video_drvdata(file
);
592 return videobuf_querybuf(&solo_dev
->vidq
, buf
);
595 static int solo_qbuf(struct file
*file
, void *priv
, struct v4l2_buffer
*buf
)
597 struct solo_dev
*solo_dev
= video_drvdata(file
);
599 return videobuf_qbuf(&solo_dev
->vidq
, buf
);
602 static int solo_dqbuf(struct file
*file
, void *priv
, struct v4l2_buffer
*buf
)
604 struct solo_dev
*solo_dev
= video_drvdata(file
);
606 return videobuf_dqbuf(&solo_dev
->vidq
, buf
, file
->f_flags
& O_NONBLOCK
);
609 static int solo_streamon(struct file
*file
, void *priv
, enum v4l2_buf_type i
)
611 struct solo_dev
*solo_dev
= video_drvdata(file
);
614 if (i
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
617 ret
= solo_start_thread(solo_dev
);
621 return videobuf_streamon(&solo_dev
->vidq
);
624 static int solo_streamoff(struct file
*file
, void *priv
, enum v4l2_buf_type i
)
626 struct solo_dev
*solo_dev
= video_drvdata(file
);
628 if (i
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
631 return videobuf_streamoff(&solo_dev
->vidq
);
634 static int solo_s_std(struct file
*file
, void *priv
, v4l2_std_id i
)
639 static int solo_s_ctrl(struct v4l2_ctrl
*ctrl
)
641 struct solo_dev
*solo_dev
=
642 container_of(ctrl
->handler
, struct solo_dev
, disp_hdl
);
645 case V4L2_CID_MOTION_TRACE
:
647 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BORDER
,
648 SOLO_VI_MOTION_Y_ADD
|
649 SOLO_VI_MOTION_Y_VALUE(0x20) |
650 SOLO_VI_MOTION_CB_VALUE(0x10) |
651 SOLO_VI_MOTION_CR_VALUE(0x10));
652 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BAR
,
653 SOLO_VI_MOTION_CR_ADD
|
654 SOLO_VI_MOTION_Y_VALUE(0x10) |
655 SOLO_VI_MOTION_CB_VALUE(0x80) |
656 SOLO_VI_MOTION_CR_VALUE(0x10));
658 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BORDER
, 0);
659 solo_reg_write(solo_dev
, SOLO_VI_MOTION_BAR
, 0);
668 static const struct v4l2_file_operations solo_v4l2_fops
= {
669 .owner
= THIS_MODULE
,
670 .open
= v4l2_fh_open
,
671 .release
= solo_v4l2_release
,
672 .read
= solo_v4l2_read
,
673 .poll
= solo_v4l2_poll
,
674 .mmap
= solo_v4l2_mmap
,
675 .ioctl
= video_ioctl2
,
678 static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops
= {
679 .vidioc_querycap
= solo_querycap
,
680 .vidioc_s_std
= solo_s_std
,
681 /* Input callbacks */
682 .vidioc_enum_input
= solo_enum_input
,
683 .vidioc_s_input
= solo_set_input
,
684 .vidioc_g_input
= solo_get_input
,
685 /* Video capture format callbacks */
686 .vidioc_enum_fmt_vid_cap
= solo_enum_fmt_cap
,
687 .vidioc_try_fmt_vid_cap
= solo_try_fmt_cap
,
688 .vidioc_s_fmt_vid_cap
= solo_set_fmt_cap
,
689 .vidioc_g_fmt_vid_cap
= solo_get_fmt_cap
,
691 .vidioc_reqbufs
= solo_reqbufs
,
692 .vidioc_querybuf
= solo_querybuf
,
693 .vidioc_qbuf
= solo_qbuf
,
694 .vidioc_dqbuf
= solo_dqbuf
,
695 .vidioc_streamon
= solo_streamon
,
696 .vidioc_streamoff
= solo_streamoff
,
697 /* Logging and events */
698 .vidioc_log_status
= v4l2_ctrl_log_status
,
699 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
700 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
703 static struct video_device solo_v4l2_template
= {
704 .name
= SOLO6X10_NAME
,
705 .fops
= &solo_v4l2_fops
,
706 .ioctl_ops
= &solo_v4l2_ioctl_ops
,
708 .release
= video_device_release
,
710 .tvnorms
= V4L2_STD_NTSC_M
| V4L2_STD_PAL_B
,
711 .current_norm
= V4L2_STD_NTSC_M
,
714 static const struct v4l2_ctrl_ops solo_ctrl_ops
= {
715 .s_ctrl
= solo_s_ctrl
,
718 static const struct v4l2_ctrl_config solo_motion_trace_ctrl
= {
719 .ops
= &solo_ctrl_ops
,
720 .id
= V4L2_CID_MOTION_TRACE
,
721 .name
= "Motion Detection Trace",
722 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
727 int solo_v4l2_init(struct solo_dev
*solo_dev
, unsigned nr
)
732 atomic_set(&solo_dev
->disp_users
, 0);
733 init_waitqueue_head(&solo_dev
->disp_thread_wait
);
735 solo_dev
->vfd
= video_device_alloc();
739 *solo_dev
->vfd
= solo_v4l2_template
;
740 solo_dev
->vfd
->v4l2_dev
= &solo_dev
->v4l2_dev
;
741 v4l2_ctrl_handler_init(&solo_dev
->disp_hdl
, 1);
742 v4l2_ctrl_new_custom(&solo_dev
->disp_hdl
, &solo_motion_trace_ctrl
, NULL
);
743 if (solo_dev
->disp_hdl
.error
)
744 return solo_dev
->disp_hdl
.error
;
745 solo_dev
->vfd
->ctrl_handler
= &solo_dev
->disp_hdl
;
746 set_bit(V4L2_FL_USE_FH_PRIO
, &solo_dev
->vfd
->flags
);
748 video_set_drvdata(solo_dev
->vfd
, solo_dev
);
750 spin_lock_init(&solo_dev
->slock
);
751 INIT_LIST_HEAD(&solo_dev
->vidq_active
);
753 videobuf_queue_dma_contig_init(&solo_dev
->vidq
, &solo_video_qops
,
754 &solo_dev
->pdev
->dev
, &solo_dev
->slock
,
755 V4L2_BUF_TYPE_VIDEO_CAPTURE
,
756 V4L2_FIELD_INTERLACED
,
757 sizeof(struct videobuf_buffer
),
760 /* Cycle all the channels and clear */
761 for (i
= 0; i
< solo_dev
->nr_chans
; i
++) {
762 solo_v4l2_set_ch(solo_dev
, i
);
763 while (erase_off(solo_dev
))
767 /* Set the default display channel */
768 solo_v4l2_set_ch(solo_dev
, 0);
769 while (erase_off(solo_dev
))
772 ret
= video_register_device(solo_dev
->vfd
, VFL_TYPE_GRABBER
, nr
);
774 video_device_release(solo_dev
->vfd
);
775 solo_dev
->vfd
= NULL
;
779 snprintf(solo_dev
->vfd
->name
, sizeof(solo_dev
->vfd
->name
), "%s (%i)",
780 SOLO6X10_NAME
, solo_dev
->vfd
->num
);
782 dev_info(&solo_dev
->pdev
->dev
, "Display as /dev/video%d with "
783 "%d inputs (%d extended)\n", solo_dev
->vfd
->num
,
784 solo_dev
->nr_chans
, solo_dev
->nr_ext
);
789 void solo_v4l2_exit(struct solo_dev
*solo_dev
)
791 if (solo_dev
->vfd
== NULL
)
794 video_unregister_device(solo_dev
->vfd
);
795 v4l2_ctrl_handler_free(&solo_dev
->disp_hdl
);
796 solo_dev
->vfd
= NULL
;