[media] solo6x10: move global fields in solo_dev_fh to solo_dev
[deliverable/linux.git] / drivers / staging / media / solo6x10 / v4l2.c
1 /*
2 * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
3 *
4 * Original author:
5 * Ben Collins <bcollins@ubuntu.com>
6 *
7 * Additional work by:
8 * John Brooks <john.brooks@bluecherry.net>
9 *
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.
14 *
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.
19 *
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.
23 */
24
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/kthread.h>
28 #include <linux/freezer.h>
29
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>
34
35 #include "solo6x10.h"
36 #include "tw28.h"
37
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) * \
42 solo_vlines(__solo))
43 #define solo_bytesperline(__solo) (__solo->video_hsize * 2)
44
45 #define MIN_VID_BUFFERS 2
46
47 static inline void erase_on(struct solo_dev *solo_dev)
48 {
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;
52 }
53
54 static inline int erase_off(struct solo_dev *solo_dev)
55 {
56 if (!solo_dev->erasing)
57 return 0;
58
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;
65
66 return 1;
67 }
68
69 void solo_video_in_isr(struct solo_dev *solo_dev)
70 {
71 wake_up_interruptible_all(&solo_dev->disp_thread_wait);
72 }
73
74 static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
75 int sx, int sy, int ex, int ey, int scale)
76 {
77 if (ch >= solo_dev->nr_chans)
78 return;
79
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) |
83 SOLO_VI_WIN_SX(sx) |
84 SOLO_VI_WIN_EX(ex) |
85 SOLO_VI_WIN_SCALE(scale));
86
87 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
88 SOLO_VI_WIN_SY(sy) |
89 SOLO_VI_WIN_EY(ey));
90 }
91
92 static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
93 {
94 u8 ch = idx * 4;
95
96 if (ch >= solo_dev->nr_chans)
97 return -EINVAL;
98
99 if (!on) {
100 u8 i;
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);
106 return 0;
107 }
108
109 /* Row 1 */
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);
114 /* Row 2 */
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);
120
121 return 0;
122 }
123
124 static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
125 {
126 int sy, ysize, hsize, i;
127
128 if (!on) {
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);
134 return 0;
135 }
136
137 ysize = solo_vlines(solo_dev) / 4;
138 hsize = solo_dev->video_hsize / 4;
139
140 for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
141 solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
142 sy + ysize, 5);
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);
149 }
150
151 return 0;
152 }
153
154 static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
155 {
156 u8 ext_ch;
157
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),
162 on ? 1 : 0);
163 return 0;
164 }
165
166 if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
167 return -EINVAL;
168
169 ext_ch = ch - solo_dev->nr_chans;
170
171 /* 4up's first */
172 if (ext_ch < 4)
173 return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
174
175 /* Remaining case is 16up for 16-port */
176 return solo_v4l2_ch_ext_16up(solo_dev, on);
177 }
178
179 static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
180 {
181 if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
182 return -EINVAL;
183
184 erase_on(solo_dev);
185
186 solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
187 solo_v4l2_ch(solo_dev, ch, 1);
188
189 solo_dev->cur_disp_ch = ch;
190
191 return 0;
192 }
193
194 static void solo_fillbuf(struct solo_dev *solo_dev,
195 struct videobuf_buffer *vb)
196 {
197 dma_addr_t vbuf;
198 unsigned int fdma_addr;
199 int error = -1;
200 int i;
201
202 vbuf = videobuf_to_dma_contig(vb);
203 if (!vbuf)
204 goto finish_buf;
205
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) {
210 ((u8 *)p)[i] = 0x80;
211 ((u8 *)p)[i + 1] = 0x00;
212 }
213 error = 0;
214 } else {
215 fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write *
216 (SOLO_HW_BPL * solo_vlines(solo_dev)));
217
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);
221 }
222
223 finish_buf:
224 if (error) {
225 vb->state = VIDEOBUF_ERROR;
226 } else {
227 vb->state = VIDEOBUF_DONE;
228 vb->field_count++;
229 }
230
231 wake_up(&vb->done);
232 }
233
234 static void solo_thread_try(struct solo_dev *solo_dev)
235 {
236 struct videobuf_buffer *vb;
237
238 /* Only "break" from this loop if slock is held, otherwise
239 * just return. */
240 for (;;) {
241 unsigned int cur_write;
242
243 cur_write = SOLO_VI_STATUS0_PAGE(
244 solo_reg_read(solo_dev, SOLO_VI_STATUS0));
245 if (cur_write == solo_dev->old_write)
246 return;
247
248 spin_lock(&solo_dev->slock);
249
250 if (list_empty(&solo_dev->vidq_active))
251 break;
252
253 vb = list_first_entry(&solo_dev->vidq_active, struct videobuf_buffer,
254 queue);
255
256 if (!waitqueue_active(&vb->done))
257 break;
258
259 solo_dev->old_write = cur_write;
260 list_del(&vb->queue);
261 vb->state = VIDEOBUF_ACTIVE;
262
263 spin_unlock(&solo_dev->slock);
264
265 solo_fillbuf(solo_dev, vb);
266 }
267
268 assert_spin_locked(&solo_dev->slock);
269 spin_unlock(&solo_dev->slock);
270 }
271
272 static int solo_thread(void *data)
273 {
274 struct solo_dev *solo_dev = data;
275 DECLARE_WAITQUEUE(wait, current);
276
277 set_freezable();
278 add_wait_queue(&solo_dev->disp_thread_wait, &wait);
279
280 for (;;) {
281 long timeout = schedule_timeout_interruptible(HZ);
282 if (timeout == -ERESTARTSYS || kthread_should_stop())
283 break;
284 solo_thread_try(solo_dev);
285 try_to_freeze();
286 }
287
288 remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
289
290 return 0;
291 }
292
293 static int solo_start_thread(struct solo_dev *solo_dev)
294 {
295 int ret = 0;
296
297 if (atomic_inc_return(&solo_dev->disp_users) == 1)
298 solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
299
300 solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp");
301
302 if (IS_ERR(solo_dev->kthread)) {
303 ret = PTR_ERR(solo_dev->kthread);
304 solo_dev->kthread = NULL;
305 }
306
307 return ret;
308 }
309
310 static void solo_stop_thread(struct solo_dev *solo_dev)
311 {
312 if (!solo_dev->kthread)
313 return;
314
315 kthread_stop(solo_dev->kthread);
316 solo_dev->kthread = NULL;
317
318 if (atomic_dec_return(&solo_dev->disp_users) == 0)
319 solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
320 }
321
322 static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
323 unsigned int *size)
324 {
325 struct solo_dev *solo_dev = vq->priv_data;
326
327 *size = solo_image_size(solo_dev);
328
329 if (*count < MIN_VID_BUFFERS)
330 *count = MIN_VID_BUFFERS;
331
332 return 0;
333 }
334
335 static int solo_buf_prepare(struct videobuf_queue *vq,
336 struct videobuf_buffer *vb, enum v4l2_field field)
337 {
338 struct solo_dev *solo_dev = vq->priv_data;
339
340 vb->size = solo_image_size(solo_dev);
341 if (vb->baddr != 0 && vb->bsize < vb->size)
342 return -EINVAL;
343
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);
348 vb->field = field;
349
350 if (vb->state == VIDEOBUF_NEEDS_INIT) {
351 int rc = videobuf_iolock(vq, vb, NULL);
352 if (rc < 0) {
353 videobuf_dma_contig_free(vq, vb);
354 vb->state = VIDEOBUF_NEEDS_INIT;
355 return rc;
356 }
357 }
358 vb->state = VIDEOBUF_PREPARED;
359
360 return 0;
361 }
362
363 static void solo_buf_queue(struct videobuf_queue *vq,
364 struct videobuf_buffer *vb)
365 {
366 struct solo_dev *solo_dev = vq->priv_data;
367
368 vb->state = VIDEOBUF_QUEUED;
369 list_add_tail(&vb->queue, &solo_dev->vidq_active);
370 wake_up_interruptible(&solo_dev->disp_thread_wait);
371 }
372
373 static void solo_buf_release(struct videobuf_queue *vq,
374 struct videobuf_buffer *vb)
375 {
376 videobuf_dma_contig_free(vq, vb);
377 vb->state = VIDEOBUF_NEEDS_INIT;
378 }
379
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,
385 };
386
387 static unsigned int solo_v4l2_poll(struct file *file,
388 struct poll_table_struct *wait)
389 {
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);
393
394 if (!(req_events & (POLLIN | POLLRDNORM)))
395 return res;
396 return res | videobuf_poll_stream(file, &solo_dev->vidq, wait);
397 }
398
399 static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
400 {
401 struct solo_dev *solo_dev = video_drvdata(file);
402
403 return videobuf_mmap_mapper(&solo_dev->vidq, vma);
404 }
405
406 static ssize_t solo_v4l2_read(struct file *file, char __user *data,
407 size_t count, loff_t *ppos)
408 {
409 struct solo_dev *solo_dev = video_drvdata(file);
410
411 return videobuf_read_stream(&solo_dev->vidq, data, count, ppos, 0,
412 file->f_flags & O_NONBLOCK);
413 }
414
415 static int solo_v4l2_release(struct file *file)
416 {
417 struct solo_dev *solo_dev = video_drvdata(file);
418
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);
423 }
424
425 static int solo_querycap(struct file *file, void *priv,
426 struct v4l2_capability *cap)
427 {
428 struct solo_dev *solo_dev = video_drvdata(file);
429
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;
437 return 0;
438 }
439
440 static int solo_enum_ext_input(struct solo_dev *solo_dev,
441 struct v4l2_input *input)
442 {
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"
447 };
448 const char * const *dispnames;
449
450 if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
451 return -EINVAL;
452
453 if (solo_dev->nr_ext == 5)
454 dispnames = dispnames_5;
455 else if (solo_dev->nr_ext == 2)
456 dispnames = dispnames_2;
457 else
458 dispnames = dispnames_1;
459
460 snprintf(input->name, sizeof(input->name), "Multi %s",
461 dispnames[input->index - solo_dev->nr_chans]);
462
463 return 0;
464 }
465
466 static int solo_enum_input(struct file *file, void *priv,
467 struct v4l2_input *input)
468 {
469 struct solo_dev *solo_dev = video_drvdata(file);
470
471 if (input->index >= solo_dev->nr_chans) {
472 int ret = solo_enum_ext_input(solo_dev, input);
473 if (ret < 0)
474 return ret;
475 } else {
476 snprintf(input->name, sizeof(input->name), "Camera %d",
477 input->index + 1);
478
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;
482 }
483
484 input->type = V4L2_INPUT_TYPE_CAMERA;
485
486 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
487 input->std = V4L2_STD_NTSC_M;
488 else
489 input->std = V4L2_STD_PAL_B;
490
491 return 0;
492 }
493
494 static int solo_set_input(struct file *file, void *priv, unsigned int index)
495 {
496 struct solo_dev *solo_dev = video_drvdata(file);
497 int ret = solo_v4l2_set_ch(solo_dev, index);
498
499 if (!ret) {
500 while (erase_off(solo_dev))
501 /* Do nothing */;
502 }
503
504 return ret;
505 }
506
507 static int solo_get_input(struct file *file, void *priv, unsigned int *index)
508 {
509 struct solo_dev *solo_dev = video_drvdata(file);
510
511 *index = solo_dev->cur_disp_ch;
512
513 return 0;
514 }
515
516 static int solo_enum_fmt_cap(struct file *file, void *priv,
517 struct v4l2_fmtdesc *f)
518 {
519 if (f->index)
520 return -EINVAL;
521
522 f->pixelformat = V4L2_PIX_FMT_UYVY;
523 strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
524
525 return 0;
526 }
527
528 static int solo_try_fmt_cap(struct file *file, void *priv,
529 struct v4l2_format *f)
530 {
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);
534
535 if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
536 return -EINVAL;
537
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;
544 pix->priv = 0;
545 return 0;
546 }
547
548 static int solo_set_fmt_cap(struct file *file, void *priv,
549 struct v4l2_format *f)
550 {
551 struct solo_dev *solo_dev = video_drvdata(file);
552
553 if (videobuf_queue_is_busy(&solo_dev->vidq))
554 return -EBUSY;
555
556 /* For right now, if it doesn't match our running config,
557 * then fail */
558 return solo_try_fmt_cap(file, priv, f);
559 }
560
561 static int solo_get_fmt_cap(struct file *file, void *priv,
562 struct v4l2_format *f)
563 {
564 struct solo_dev *solo_dev = video_drvdata(file);
565 struct v4l2_pix_format *pix = &f->fmt.pix;
566
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);
574 pix->priv = 0;
575
576 return 0;
577 }
578
579 static int solo_reqbufs(struct file *file, void *priv,
580 struct v4l2_requestbuffers *req)
581 {
582 struct solo_dev *solo_dev = video_drvdata(file);
583
584 return videobuf_reqbufs(&solo_dev->vidq, req);
585 }
586
587 static int solo_querybuf(struct file *file, void *priv,
588 struct v4l2_buffer *buf)
589 {
590 struct solo_dev *solo_dev = video_drvdata(file);
591
592 return videobuf_querybuf(&solo_dev->vidq, buf);
593 }
594
595 static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
596 {
597 struct solo_dev *solo_dev = video_drvdata(file);
598
599 return videobuf_qbuf(&solo_dev->vidq, buf);
600 }
601
602 static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
603 {
604 struct solo_dev *solo_dev = video_drvdata(file);
605
606 return videobuf_dqbuf(&solo_dev->vidq, buf, file->f_flags & O_NONBLOCK);
607 }
608
609 static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
610 {
611 struct solo_dev *solo_dev = video_drvdata(file);
612 int ret;
613
614 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
615 return -EINVAL;
616
617 ret = solo_start_thread(solo_dev);
618 if (ret)
619 return ret;
620
621 return videobuf_streamon(&solo_dev->vidq);
622 }
623
624 static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
625 {
626 struct solo_dev *solo_dev = video_drvdata(file);
627
628 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
629 return -EINVAL;
630
631 return videobuf_streamoff(&solo_dev->vidq);
632 }
633
634 static int solo_s_std(struct file *file, void *priv, v4l2_std_id i)
635 {
636 return 0;
637 }
638
639 static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
640 {
641 struct solo_dev *solo_dev =
642 container_of(ctrl->handler, struct solo_dev, disp_hdl);
643
644 switch (ctrl->id) {
645 case V4L2_CID_MOTION_TRACE:
646 if (ctrl->val) {
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));
657 } else {
658 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
659 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
660 }
661 return 0;
662 default:
663 break;
664 }
665 return -EINVAL;
666 }
667
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,
676 };
677
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,
690 /* Streaming I/O */
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,
701 };
702
703 static struct video_device solo_v4l2_template = {
704 .name = SOLO6X10_NAME,
705 .fops = &solo_v4l2_fops,
706 .ioctl_ops = &solo_v4l2_ioctl_ops,
707 .minor = -1,
708 .release = video_device_release,
709
710 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
711 .current_norm = V4L2_STD_NTSC_M,
712 };
713
714 static const struct v4l2_ctrl_ops solo_ctrl_ops = {
715 .s_ctrl = solo_s_ctrl,
716 };
717
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,
723 .max = 1,
724 .step = 1,
725 };
726
727 int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
728 {
729 int ret;
730 int i;
731
732 atomic_set(&solo_dev->disp_users, 0);
733 init_waitqueue_head(&solo_dev->disp_thread_wait);
734
735 solo_dev->vfd = video_device_alloc();
736 if (!solo_dev->vfd)
737 return -ENOMEM;
738
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);
747
748 video_set_drvdata(solo_dev->vfd, solo_dev);
749
750 spin_lock_init(&solo_dev->slock);
751 INIT_LIST_HEAD(&solo_dev->vidq_active);
752
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),
758 solo_dev, NULL);
759
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))
764 /* Do nothing */;
765 }
766
767 /* Set the default display channel */
768 solo_v4l2_set_ch(solo_dev, 0);
769 while (erase_off(solo_dev))
770 /* Do nothing */;
771
772 ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
773 if (ret < 0) {
774 video_device_release(solo_dev->vfd);
775 solo_dev->vfd = NULL;
776 return ret;
777 }
778
779 snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
780 SOLO6X10_NAME, solo_dev->vfd->num);
781
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);
785
786 return 0;
787 }
788
789 void solo_v4l2_exit(struct solo_dev *solo_dev)
790 {
791 if (solo_dev->vfd == NULL)
792 return;
793
794 video_unregister_device(solo_dev->vfd);
795 v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
796 solo_dev->vfd = NULL;
797 }
This page took 0.050866 seconds and 5 git commands to generate.