Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.git] / drivers / staging / solo6x10 / solo6010-v4l2.c
1 /*
2  * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
3  * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/kthread.h>
23 #include <linux/freezer.h>
24
25 #include <media/v4l2-ioctl.h>
26 #include <media/v4l2-common.h>
27 #include <media/videobuf-dma-contig.h>
28
29 #include "solo6010.h"
30 #include "solo6010-tw28.h"
31
32 #define SOLO_HW_BPL             2048
33 #define SOLO_DISP_PIX_FIELD     V4L2_FIELD_INTERLACED
34 #define SOLO_DISP_BUF_SIZE      (64 * 1024) // 64k
35
36 /* Image size is two fields, SOLO_HW_BPL is one horizontal line */
37 #define solo_vlines(__solo)     (__solo->video_vsize * 2)
38 #define solo_image_size(__solo) (solo_bytesperline(__solo) * \
39                                  solo_vlines(__solo))
40 #define solo_bytesperline(__solo) (__solo->video_hsize * 2)
41
42 #define MIN_VID_BUFFERS         4
43
44 /* Simple file handle */
45 struct solo_filehandle {
46         struct solo6010_dev     *solo_dev;
47         struct videobuf_queue   vidq;
48         struct task_struct      *kthread;
49         spinlock_t              slock;
50         int                     old_write;
51         struct list_head        vidq_active;
52 };
53
54 unsigned video_nr = -1;
55 module_param(video_nr, uint, 0644);
56 MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
57
58 static void erase_on(struct solo6010_dev *solo_dev)
59 {
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;
63 }
64
65 static int erase_off(struct solo6010_dev *solo_dev)
66 {
67         if (!solo_dev->erasing)
68                 return 0;
69
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;
76
77         return 1;
78 }
79
80 void solo_video_in_isr(struct solo6010_dev *solo_dev)
81 {
82         solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
83         wake_up_interruptible(&solo_dev->disp_thread_wait);
84 }
85
86 static void solo_win_setup(struct solo6010_dev *solo_dev, u8 ch,
87                            int sx, int sy, int ex, int ey, int scale)
88 {
89         if (ch >= solo_dev->nr_chans)
90                 return;
91
92         /* Here, we just keep window/channel the same */
93         solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
94                        SOLO_VI_WIN_CHANNEL(ch) |
95                        SOLO_VI_WIN_SX(sx) |
96                        SOLO_VI_WIN_EX(ex) |
97                        SOLO_VI_WIN_SCALE(scale));
98
99         solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
100                        SOLO_VI_WIN_SY(sy) |
101                        SOLO_VI_WIN_EY(ey));
102 }
103
104 static int solo_v4l2_ch_ext_4up(struct solo6010_dev *solo_dev, u8 idx, int on)
105 {
106         u8 ch = idx * 4;
107
108         if (ch >= solo_dev->nr_chans)
109                 return -EINVAL;
110
111         if (!on) {
112                 u8 i;
113                 for (i = ch; i < ch + 4; i++)
114                         solo_win_setup(solo_dev, i, solo_dev->video_hsize,
115                                        solo_vlines(solo_dev),
116                                        solo_dev->video_hsize,
117                                        solo_vlines(solo_dev), 0);
118                 return 0;
119         }
120
121         /* Row 1 */
122         solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
123                        solo_vlines(solo_dev) / 2, 3);
124         solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
125                        solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
126         /* Row 2 */
127         solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
128                        solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
129         solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
130                        solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
131                        solo_vlines(solo_dev), 3);
132
133         return 0;
134 }
135
136 static int solo_v4l2_ch_ext_16up(struct solo6010_dev *solo_dev, int on)
137 {
138         int sy, ysize, hsize, i;
139
140         if (!on) {
141                 for (i = 0; i < 16; i++)
142                         solo_win_setup(solo_dev, i, solo_dev->video_hsize,
143                                        solo_vlines(solo_dev),
144                                        solo_dev->video_hsize,
145                                        solo_vlines(solo_dev), 0);
146                 return 0;
147         }
148
149         ysize = solo_vlines(solo_dev) / 4;
150         hsize = solo_dev->video_hsize / 4;
151
152         for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
153                 solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
154                                sy + ysize, 5);
155                 solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
156                                hsize * 2, sy + ysize, 5);
157                 solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
158                                hsize * 3, sy + ysize, 5);
159                 solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
160                                solo_dev->video_hsize, sy + ysize, 5);
161         }
162
163         return 0;
164 }
165
166 static int solo_v4l2_ch(struct solo6010_dev *solo_dev, u8 ch, int on)
167 {
168         u8 ext_ch;
169
170         if (ch < solo_dev->nr_chans) {
171                 solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
172                                on ? 0 : solo_vlines(solo_dev),
173                                solo_dev->video_hsize, solo_vlines(solo_dev),
174                                on ? 1 : 0);
175                 return 0;
176         }
177
178         if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
179                 return -EINVAL;
180
181         ext_ch = ch - solo_dev->nr_chans;
182
183         /* 4up's first */
184         if (ext_ch < 4)
185                 return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
186
187         /* Remaining case is 16up for 16-port */
188         return solo_v4l2_ch_ext_16up(solo_dev, on);
189 }
190
191 static int solo_v4l2_set_ch(struct solo6010_dev *solo_dev, u8 ch)
192 {
193         if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
194                 return -EINVAL;
195
196         erase_on(solo_dev);
197
198         solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
199         solo_v4l2_ch(solo_dev, ch, 1);
200
201         solo_dev->cur_disp_ch = ch;
202
203         return 0;
204 }
205
206 static void solo_fillbuf(struct solo_filehandle *fh,
207                          struct videobuf_buffer *vb)
208 {
209         struct solo6010_dev *solo_dev = fh->solo_dev;
210         dma_addr_t vbuf;
211         unsigned int fdma_addr;
212         int frame_size;
213         int error = 1;
214         int i;
215
216         if (!(vbuf = videobuf_to_dma_contig(vb)))
217                 goto finish_buf;
218
219         if (erase_off(solo_dev)) {
220                 void *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
221                 int image_size = solo_image_size(solo_dev);
222                 for (i = 0; i < image_size; i += 2) {
223                         ((u8 *)p)[i] = 0x80;
224                         ((u8 *)p)[i + 1] = 0x00;
225                 }
226                 error = 0;
227                 goto finish_buf;
228         }
229
230         frame_size = SOLO_HW_BPL * solo_vlines(solo_dev);
231         fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write * frame_size);
232
233         for (i = 0; i < frame_size / SOLO_DISP_BUF_SIZE; i++) {
234                 int j;
235                 for (j = 0; j < (SOLO_DISP_BUF_SIZE / SOLO_HW_BPL); j++) {
236                         if (solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_DISP, 0,
237                                            vbuf, fdma_addr + (j * SOLO_HW_BPL),
238                                            solo_bytesperline(solo_dev)))
239                                 goto finish_buf;
240                         vbuf += solo_bytesperline(solo_dev);
241                 }
242                 fdma_addr += SOLO_DISP_BUF_SIZE;
243         }
244         error = 0;
245
246 finish_buf:
247         if (error) {
248                 vb->state = VIDEOBUF_ERROR;
249         } else {
250                 vb->state = VIDEOBUF_DONE;
251                 vb->field_count++;
252                 do_gettimeofday(&vb->ts);
253         }
254
255         wake_up(&vb->done);
256
257         return;
258 }
259
260 static void solo_thread_try(struct solo_filehandle *fh)
261 {
262         struct videobuf_buffer *vb;
263         unsigned int cur_write;
264
265         for (;;) {
266                 spin_lock(&fh->slock);
267
268                 if (list_empty(&fh->vidq_active))
269                         break;
270
271                 vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
272                                       queue);
273
274                 if (!waitqueue_active(&vb->done))
275                         break;
276
277                 cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
278                                                         SOLO_VI_STATUS0));
279                 if (cur_write == fh->old_write)
280                         break;
281
282                 fh->old_write = cur_write;
283                 list_del(&vb->queue);
284
285                 spin_unlock(&fh->slock);
286
287                 solo_fillbuf(fh, vb);
288         }
289
290         assert_spin_locked(&fh->slock);
291         spin_unlock(&fh->slock);
292 }
293
294 static int solo_thread(void *data)
295 {
296         struct solo_filehandle *fh = data;
297         struct solo6010_dev *solo_dev = fh->solo_dev;
298         DECLARE_WAITQUEUE(wait, current);
299
300         set_freezable();
301         add_wait_queue(&solo_dev->disp_thread_wait, &wait);
302
303         for (;;) {
304                 long timeout = schedule_timeout_interruptible(HZ);
305                 if (timeout == -ERESTARTSYS || kthread_should_stop())
306                         break;
307                 solo_thread_try(fh);
308                 try_to_freeze();
309         }
310
311         remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
312
313         return 0;
314 }
315
316 static int solo_start_thread(struct solo_filehandle *fh)
317 {
318         fh->kthread = kthread_run(solo_thread, fh, SOLO6010_NAME "_disp");
319
320         if (IS_ERR(fh->kthread))
321                 return PTR_ERR(fh->kthread);
322
323         return 0;
324 }
325
326 static void solo_stop_thread(struct solo_filehandle *fh)
327 {
328         if (fh->kthread) {
329                 kthread_stop(fh->kthread);
330                 fh->kthread = NULL;
331         }
332 }
333
334 static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
335                           unsigned int *size)
336 {
337         struct solo_filehandle *fh = vq->priv_data;
338         struct solo6010_dev *solo_dev  = fh->solo_dev;
339
340         *size = solo_image_size(solo_dev);
341
342         if (*count < MIN_VID_BUFFERS)
343                 *count = MIN_VID_BUFFERS;
344
345         return 0;
346 }
347
348 static int solo_buf_prepare(struct videobuf_queue *vq,
349                             struct videobuf_buffer *vb, enum v4l2_field field)
350 {
351         struct solo_filehandle *fh  = vq->priv_data;
352         struct solo6010_dev *solo_dev = fh->solo_dev;
353
354         vb->size = solo_image_size(solo_dev);
355         if (vb->baddr != 0 && vb->bsize < vb->size)
356                 return -EINVAL;
357
358         /* XXX: These properties only change when queue is idle */
359         vb->width  = solo_dev->video_hsize;
360         vb->height = solo_vlines(solo_dev);
361         vb->bytesperline = solo_bytesperline(solo_dev);
362         vb->field  = field;
363
364         if (vb->state == VIDEOBUF_NEEDS_INIT) {
365                 int rc = videobuf_iolock(vq, vb, NULL);
366                 if (rc < 0) {
367                         videobuf_dma_contig_free(vq, vb);
368                         vb->state = VIDEOBUF_NEEDS_INIT;
369                         return rc;
370                 }
371         }
372         vb->state = VIDEOBUF_PREPARED;
373
374         return 0;
375 }
376
377 static void solo_buf_queue(struct videobuf_queue *vq,
378                            struct videobuf_buffer *vb)
379 {
380         struct solo_filehandle *fh = vq->priv_data;
381         struct solo6010_dev *solo_dev = fh->solo_dev;
382
383         vb->state = VIDEOBUF_QUEUED;
384         list_add_tail(&vb->queue, &fh->vidq_active);
385         wake_up_interruptible(&solo_dev->disp_thread_wait);
386 }
387
388 static void solo_buf_release(struct videobuf_queue *vq,
389                              struct videobuf_buffer *vb)
390 {
391         videobuf_dma_contig_free(vq, vb);
392         vb->state = VIDEOBUF_NEEDS_INIT;
393 }
394
395 static struct videobuf_queue_ops solo_video_qops = {
396         .buf_setup      = solo_buf_setup,
397         .buf_prepare    = solo_buf_prepare,
398         .buf_queue      = solo_buf_queue,
399         .buf_release    = solo_buf_release,
400 };
401
402 static unsigned int solo_v4l2_poll(struct file *file,
403                                    struct poll_table_struct *wait)
404 {
405         struct solo_filehandle *fh = file->private_data;
406
407         return videobuf_poll_stream(file, &fh->vidq, wait);
408 }
409
410 static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
411 {
412         struct solo_filehandle *fh = file->private_data;
413
414         return videobuf_mmap_mapper(&fh->vidq, vma);
415 }
416
417 static int solo_v4l2_open(struct file *file)
418 {
419         struct solo6010_dev *solo_dev = video_drvdata(file);
420         struct solo_filehandle *fh;
421         int ret;
422
423         if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL)
424                 return -ENOMEM;
425
426         spin_lock_init(&fh->slock);
427         INIT_LIST_HEAD(&fh->vidq_active);
428         fh->solo_dev = solo_dev;
429         file->private_data = fh;
430
431         if ((ret = solo_start_thread(fh))) {
432                 kfree(fh);
433                 return ret;
434         }
435
436         videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops,
437                                     &solo_dev->pdev->dev, &fh->slock,
438                                     V4L2_BUF_TYPE_VIDEO_CAPTURE,
439                                     SOLO_DISP_PIX_FIELD,
440                                     sizeof(struct videobuf_buffer), fh);
441
442         return 0;
443 }
444
445 static ssize_t solo_v4l2_read(struct file *file, char __user *data,
446                               size_t count, loff_t *ppos)
447 {
448         struct solo_filehandle *fh = file->private_data;
449
450         return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
451                                     file->f_flags & O_NONBLOCK);
452 }
453
454 static int solo_v4l2_release(struct file *file)
455 {
456         struct solo_filehandle *fh = file->private_data;
457
458         videobuf_stop(&fh->vidq);
459         videobuf_mmap_free(&fh->vidq);
460         solo_stop_thread(fh);
461         kfree(fh);
462
463         return 0;
464 }
465
466 static int solo_querycap(struct file *file, void  *priv,
467                          struct v4l2_capability *cap)
468 {
469         struct solo_filehandle  *fh  = priv;
470         struct solo6010_dev *solo_dev = fh->solo_dev;
471
472         strcpy(cap->driver, SOLO6010_NAME);
473         strcpy(cap->card, "Softlogic 6010");
474         snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
475                  pci_name(solo_dev->pdev));
476         cap->version = SOLO6010_VER_NUM;
477         cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
478                                 V4L2_CAP_READWRITE |
479                                 V4L2_CAP_STREAMING;
480         return 0;
481 }
482
483 static int solo_enum_ext_input(struct solo6010_dev *solo_dev,
484                                struct v4l2_input *input)
485 {
486         static const char *dispnames_1[] = { "4UP" };
487         static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
488         static const char *dispnames_5[] = {
489                 "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
490         };
491         const char **dispnames;
492
493         if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
494                 return -EINVAL;
495
496         if (solo_dev->nr_ext == 5)
497                 dispnames = dispnames_5;
498         else if (solo_dev->nr_ext == 2)
499                 dispnames = dispnames_2;
500         else
501                 dispnames = dispnames_1;
502
503         snprintf(input->name, sizeof(input->name), "Multi %s",
504                  dispnames[input->index - solo_dev->nr_chans]);
505
506         return 0;
507 }
508
509 static int solo_enum_input(struct file *file, void *priv,
510                            struct v4l2_input *input)
511 {
512         struct solo_filehandle *fh  = priv;
513         struct solo6010_dev *solo_dev = fh->solo_dev;
514
515         if (input->index >= solo_dev->nr_chans) {
516                 int ret = solo_enum_ext_input(solo_dev, input);
517                 if (ret < 0)
518                         return ret;
519         } else {
520                 snprintf(input->name, sizeof(input->name), "Camera %d",
521                          input->index + 1);
522
523                 /* We can only check this for normal inputs */
524                 if (!tw28_get_video_status(solo_dev, input->index))
525                         input->status = V4L2_IN_ST_NO_SIGNAL;
526         }
527
528         input->type = V4L2_INPUT_TYPE_CAMERA;
529
530         if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
531                 input->std = V4L2_STD_NTSC_M;
532         else
533                 input->std = V4L2_STD_PAL_M;
534
535         return 0;
536 }
537
538 static int solo_set_input(struct file *file, void *priv, unsigned int index)
539 {
540         struct solo_filehandle *fh = priv;
541
542         return solo_v4l2_set_ch(fh->solo_dev, index);
543 }
544
545 static int solo_get_input(struct file *file, void *priv, unsigned int *index)
546 {
547         struct solo_filehandle *fh = priv;
548
549         *index = fh->solo_dev->cur_disp_ch;
550
551         return 0;
552 }
553
554 static int solo_enum_fmt_cap(struct file *file, void *priv,
555                              struct v4l2_fmtdesc *f)
556 {
557         if (f->index)
558                 return -EINVAL;
559
560         f->pixelformat = V4L2_PIX_FMT_UYVY;
561         strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
562
563         return 0;
564 }
565
566 static int solo_try_fmt_cap(struct file *file, void *priv,
567                             struct v4l2_format *f)
568 {
569         struct solo_filehandle *fh = priv;
570         struct solo6010_dev *solo_dev = fh->solo_dev;
571         struct v4l2_pix_format *pix = &f->fmt.pix;
572         int image_size = solo_image_size(solo_dev);
573
574         /* Check supported sizes */
575         if (pix->width != solo_dev->video_hsize)
576                 pix->width = solo_dev->video_hsize;
577         if (pix->height != solo_vlines(solo_dev))
578                 pix->height = solo_vlines(solo_dev);
579         if (pix->sizeimage != image_size)
580                 pix->sizeimage = image_size;
581
582         /* Check formats */
583         if (pix->field == V4L2_FIELD_ANY)
584                 pix->field = SOLO_DISP_PIX_FIELD;
585
586         if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
587             pix->field       != SOLO_DISP_PIX_FIELD ||
588             pix->colorspace  != V4L2_COLORSPACE_SMPTE170M)
589                 return -EINVAL;
590
591         return 0;
592 }
593
594 static int solo_set_fmt_cap(struct file *file, void *priv,
595                             struct v4l2_format *f)
596 {
597         struct solo_filehandle *fh = priv;
598
599         if (videobuf_queue_is_busy(&fh->vidq))
600                 return -EBUSY;
601
602         /* For right now, if it doesn't match our running config,
603          * then fail */
604         return solo_try_fmt_cap(file, priv, f);
605 }
606
607 static int solo_get_fmt_cap(struct file *file, void *priv,
608                             struct v4l2_format *f)
609 {
610         struct solo_filehandle *fh = priv;
611         struct solo6010_dev *solo_dev = fh->solo_dev;
612         struct v4l2_pix_format *pix = &f->fmt.pix;
613
614         pix->width = solo_dev->video_hsize;
615         pix->height = solo_vlines(solo_dev);
616         pix->pixelformat = V4L2_PIX_FMT_UYVY;
617         pix->field = SOLO_DISP_PIX_FIELD;
618         pix->sizeimage = solo_image_size(solo_dev);
619         pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
620         pix->bytesperline = solo_bytesperline(solo_dev);
621
622         return 0;
623 }
624
625 static int solo_reqbufs(struct file *file, void *priv, 
626                         struct v4l2_requestbuffers *req)
627 {
628         struct solo_filehandle *fh = priv;
629
630         return videobuf_reqbufs(&fh->vidq, req);
631 }
632
633 static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
634 {
635         struct solo_filehandle *fh = priv;
636
637         return videobuf_querybuf(&fh->vidq, buf);
638 }
639
640 static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
641 {
642         struct solo_filehandle *fh = priv;
643
644         return videobuf_qbuf(&fh->vidq, buf);
645 }
646
647 static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
648 {
649         struct solo_filehandle *fh = priv;
650
651         return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
652 }
653
654 static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
655 {
656         struct solo_filehandle *fh = priv;
657
658         if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
659                 return -EINVAL;
660
661         return videobuf_streamon(&fh->vidq);
662 }
663
664 static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
665 {
666         struct solo_filehandle *fh = priv;
667
668         if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
669                 return -EINVAL;
670
671         return videobuf_streamoff(&fh->vidq);
672 }
673
674 static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
675 {
676         return 0;
677 }
678
679 static const u32 solo_motion_ctrls[] = {
680         V4L2_CID_MOTION_TRACE,
681         0
682 };
683
684 static const u32 *solo_ctrl_classes[] = {
685         solo_motion_ctrls,
686         NULL
687 };
688
689 static int solo_disp_queryctrl(struct file *file, void *priv,
690                                struct v4l2_queryctrl *qc)
691 {
692         qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
693         if (!qc->id)
694                 return -EINVAL;
695
696         switch (qc->id) {
697 #ifdef PRIVATE_CIDS
698         case V4L2_CID_MOTION_TRACE:
699                 qc->type = V4L2_CTRL_TYPE_BOOLEAN;
700                 qc->minimum = 0;
701                 qc->maximum = qc->step = 1;
702                 qc->default_value = 0;
703                 strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
704                 return 0;
705 #else
706         case V4L2_CID_MOTION_TRACE:
707                 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
708 #endif
709         }
710         return -EINVAL;
711 }
712
713 static int solo_disp_g_ctrl(struct file *file, void *priv,
714                             struct v4l2_control *ctrl)
715 {
716         struct solo_filehandle *fh = priv;
717         struct solo6010_dev *solo_dev = fh->solo_dev;
718
719         switch (ctrl->id) {
720         case V4L2_CID_MOTION_TRACE:
721                 ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
722                         ? 1 : 0;
723                 return 0;
724         }
725         return -EINVAL;
726 }
727
728 static int solo_disp_s_ctrl(struct file *file, void *priv,
729                             struct v4l2_control *ctrl)
730 {
731         struct solo_filehandle *fh = priv;
732         struct solo6010_dev *solo_dev = fh->solo_dev;
733
734         switch (ctrl->id) {
735         case V4L2_CID_MOTION_TRACE:
736                 if (ctrl->value) {
737                         solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
738                                         SOLO_VI_MOTION_Y_ADD |
739                                         SOLO_VI_MOTION_Y_VALUE(0x20) |
740                                         SOLO_VI_MOTION_CB_VALUE(0x10) |
741                                         SOLO_VI_MOTION_CR_VALUE(0x10));
742                         solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
743                                         SOLO_VI_MOTION_CR_ADD |
744                                         SOLO_VI_MOTION_Y_VALUE(0x10) |
745                                         SOLO_VI_MOTION_CB_VALUE(0x80) |
746                                         SOLO_VI_MOTION_CR_VALUE(0x10));
747                 } else {
748                         solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
749                         solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
750                 }
751                 return 0;
752         }
753         return -EINVAL;
754 }
755
756 static const struct v4l2_file_operations solo_v4l2_fops = {
757         .owner                  = THIS_MODULE,
758         .open                   = solo_v4l2_open,
759         .release                = solo_v4l2_release,
760         .read                   = solo_v4l2_read,
761         .poll                   = solo_v4l2_poll,
762         .mmap                   = solo_v4l2_mmap,
763         .ioctl                  = video_ioctl2,
764 };
765
766 static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
767         .vidioc_querycap                = solo_querycap,
768         .vidioc_s_std                   = solo_s_std,
769         /* Input callbacks */
770         .vidioc_enum_input              = solo_enum_input,
771         .vidioc_s_input                 = solo_set_input,
772         .vidioc_g_input                 = solo_get_input,
773         /* Video capture format callbacks */
774         .vidioc_enum_fmt_vid_cap        = solo_enum_fmt_cap,
775         .vidioc_try_fmt_vid_cap         = solo_try_fmt_cap,
776         .vidioc_s_fmt_vid_cap           = solo_set_fmt_cap,
777         .vidioc_g_fmt_vid_cap           = solo_get_fmt_cap,
778         /* Streaming I/O */
779         .vidioc_reqbufs                 = solo_reqbufs,
780         .vidioc_querybuf                = solo_querybuf,
781         .vidioc_qbuf                    = solo_qbuf,
782         .vidioc_dqbuf                   = solo_dqbuf,
783         .vidioc_streamon                = solo_streamon,
784         .vidioc_streamoff               = solo_streamoff,
785         /* Controls */
786         .vidioc_queryctrl               = solo_disp_queryctrl,
787         .vidioc_g_ctrl                  = solo_disp_g_ctrl,
788         .vidioc_s_ctrl                  = solo_disp_s_ctrl,
789 };
790
791 static struct video_device solo_v4l2_template = {
792         .name                   = SOLO6010_NAME,
793         .fops                   = &solo_v4l2_fops,
794         .ioctl_ops              = &solo_v4l2_ioctl_ops,
795         .minor                  = -1,
796         .release                = video_device_release,
797
798         .tvnorms                = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
799         .current_norm           = V4L2_STD_NTSC_M,
800 };
801
802 int solo_v4l2_init(struct solo6010_dev *solo_dev)
803 {
804         int ret;
805         int i;
806
807         init_waitqueue_head(&solo_dev->disp_thread_wait);
808
809         solo_dev->vfd = video_device_alloc();
810         if (!solo_dev->vfd)
811                 return -ENOMEM;
812
813         *solo_dev->vfd = solo_v4l2_template;
814         solo_dev->vfd->parent = &solo_dev->pdev->dev;
815
816         ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
817         if (ret < 0) {
818                 video_device_release(solo_dev->vfd);
819                 solo_dev->vfd = NULL;
820                 return ret;
821         }
822
823         video_set_drvdata(solo_dev->vfd, solo_dev);
824
825         snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
826                  SOLO6010_NAME, solo_dev->vfd->num);
827
828         if (video_nr != -1)
829                 video_nr++;
830
831         dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
832                  "%d inputs (%d extended)\n", solo_dev->vfd->num,
833                  solo_dev->nr_chans, solo_dev->nr_ext);
834
835         /* Cycle all the channels and clear */
836         for (i = 0; i < solo_dev->nr_chans; i++) {
837                 solo_v4l2_set_ch(solo_dev, i);
838                 while (erase_off(solo_dev))
839                         ;// Do nothing
840         }
841
842         /* Set the default display channel */
843         solo_v4l2_set_ch(solo_dev, 0);
844         while (erase_off(solo_dev))
845                 ;// Do nothing
846
847         solo6010_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
848
849         return 0;
850 }
851
852 void solo_v4l2_exit(struct solo6010_dev *solo_dev)
853 {
854         solo6010_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
855         if (solo_dev->vfd) {
856                 video_unregister_device(solo_dev->vfd);
857                 solo_dev->vfd = NULL;
858         }
859 }