1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/module.h>
20#include <media/v4l2-common.h>
21#include <media/v4l2-event.h>
22#include <media/videobuf2-dma-sg.h>
23
24#include "tw68.h"
25#include "tw68-reg.h"
26
27
28
29
30
31
32
33
34
35static const struct tw68_format formats[] = {
36 {
37 .fourcc = V4L2_PIX_FMT_RGB555,
38 .depth = 16,
39 .twformat = ColorFormatRGB15,
40 }, {
41 .fourcc = V4L2_PIX_FMT_RGB555X,
42 .depth = 16,
43 .twformat = ColorFormatRGB15 | ColorFormatBSWAP,
44 }, {
45 .fourcc = V4L2_PIX_FMT_RGB565,
46 .depth = 16,
47 .twformat = ColorFormatRGB16,
48 }, {
49 .fourcc = V4L2_PIX_FMT_RGB565X,
50 .depth = 16,
51 .twformat = ColorFormatRGB16 | ColorFormatBSWAP,
52 }, {
53 .fourcc = V4L2_PIX_FMT_BGR24,
54 .depth = 24,
55 .twformat = ColorFormatRGB24,
56 }, {
57 .fourcc = V4L2_PIX_FMT_RGB24,
58 .depth = 24,
59 .twformat = ColorFormatRGB24 | ColorFormatBSWAP,
60 }, {
61 .fourcc = V4L2_PIX_FMT_BGR32,
62 .depth = 32,
63 .twformat = ColorFormatRGB32,
64 }, {
65 .fourcc = V4L2_PIX_FMT_RGB32,
66 .depth = 32,
67 .twformat = ColorFormatRGB32 | ColorFormatBSWAP |
68 ColorFormatWSWAP,
69 }, {
70 .fourcc = V4L2_PIX_FMT_YUYV,
71 .depth = 16,
72 .twformat = ColorFormatYUY2,
73 }, {
74 .fourcc = V4L2_PIX_FMT_UYVY,
75 .depth = 16,
76 .twformat = ColorFormatYUY2 | ColorFormatBSWAP,
77 }
78};
79#define FORMATS ARRAY_SIZE(formats)
80
81#define NORM_625_50 \
82 .h_delay = 3, \
83 .h_delay0 = 133, \
84 .h_start = 0, \
85 .h_stop = 719, \
86 .v_delay = 24, \
87 .vbi_v_start_0 = 7, \
88 .vbi_v_stop_0 = 22, \
89 .video_v_start = 24, \
90 .video_v_stop = 311, \
91 .vbi_v_start_1 = 319
92
93#define NORM_525_60 \
94 .h_delay = 8, \
95 .h_delay0 = 138, \
96 .h_start = 0, \
97 .h_stop = 719, \
98 .v_delay = 22, \
99 .vbi_v_start_0 = 10, \
100 .vbi_v_stop_0 = 21, \
101 .video_v_start = 22, \
102 .video_v_stop = 262, \
103 .vbi_v_start_1 = 273
104
105
106
107
108
109
110static const struct tw68_tvnorm tvnorms[] = {
111 {
112 .name = "PAL",
113 .id = V4L2_STD_PAL,
114 NORM_625_50,
115
116 .sync_control = 0x18,
117 .luma_control = 0x40,
118 .chroma_ctrl1 = 0x81,
119 .chroma_gain = 0x2a,
120 .chroma_ctrl2 = 0x06,
121 .vgate_misc = 0x1c,
122 .format = VideoFormatPALBDGHI,
123 }, {
124 .name = "NTSC",
125 .id = V4L2_STD_NTSC,
126 NORM_525_60,
127
128 .sync_control = 0x59,
129 .luma_control = 0x40,
130 .chroma_ctrl1 = 0x89,
131 .chroma_gain = 0x2a,
132 .chroma_ctrl2 = 0x0e,
133 .vgate_misc = 0x18,
134 .format = VideoFormatNTSC,
135 }, {
136 .name = "SECAM",
137 .id = V4L2_STD_SECAM,
138 NORM_625_50,
139
140 .sync_control = 0x18,
141 .luma_control = 0x1b,
142 .chroma_ctrl1 = 0xd1,
143 .chroma_gain = 0x80,
144 .chroma_ctrl2 = 0x00,
145 .vgate_misc = 0x1c,
146 .format = VideoFormatSECAM,
147 }, {
148 .name = "PAL-M",
149 .id = V4L2_STD_PAL_M,
150 NORM_525_60,
151
152 .sync_control = 0x59,
153 .luma_control = 0x40,
154 .chroma_ctrl1 = 0xb9,
155 .chroma_gain = 0x2a,
156 .chroma_ctrl2 = 0x0e,
157 .vgate_misc = 0x18,
158 .format = VideoFormatPALM,
159 }, {
160 .name = "PAL-Nc",
161 .id = V4L2_STD_PAL_Nc,
162 NORM_625_50,
163
164 .sync_control = 0x18,
165 .luma_control = 0x40,
166 .chroma_ctrl1 = 0xa1,
167 .chroma_gain = 0x2a,
168 .chroma_ctrl2 = 0x06,
169 .vgate_misc = 0x1c,
170 .format = VideoFormatPALNC,
171 }, {
172 .name = "PAL-60",
173 .id = V4L2_STD_PAL_60,
174 .h_delay = 186,
175 .h_start = 0,
176 .h_stop = 719,
177 .v_delay = 26,
178 .video_v_start = 23,
179 .video_v_stop = 262,
180 .vbi_v_start_0 = 10,
181 .vbi_v_stop_0 = 21,
182 .vbi_v_start_1 = 273,
183
184 .sync_control = 0x18,
185 .luma_control = 0x40,
186 .chroma_ctrl1 = 0x81,
187 .chroma_gain = 0x2a,
188 .chroma_ctrl2 = 0x06,
189 .vgate_misc = 0x1c,
190 .format = VideoFormatPAL60,
191 }
192};
193#define TVNORMS ARRAY_SIZE(tvnorms)
194
195static const struct tw68_format *format_by_fourcc(unsigned int fourcc)
196{
197 unsigned int i;
198
199 for (i = 0; i < FORMATS; i++)
200 if (formats[i].fourcc == fourcc)
201 return formats+i;
202 return NULL;
203}
204
205
206
207
208
209
210
211static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)
212{
213 if (norm != dev->tvnorm) {
214 dev->width = 720;
215 dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576;
216 dev->tvnorm = norm;
217 tw68_set_tvnorm_hw(dev);
218 }
219}
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,
251 unsigned int height, enum v4l2_field field)
252{
253 const struct tw68_tvnorm *norm = dev->tvnorm;
254
255 int hactive, hdelay, hscale;
256 int vactive, vdelay, vscale;
257 int comb;
258
259 if (V4L2_FIELD_HAS_BOTH(field))
260 height /= 2;
261
262 pr_debug("%s: width=%d, height=%d, both=%d\n"
263 " tvnorm h_delay=%d, h_start=%d, h_stop=%d, v_delay=%d, v_start=%d, v_stop=%d\n",
264 __func__, width, height, V4L2_FIELD_HAS_BOTH(field),
265 norm->h_delay, norm->h_start, norm->h_stop,
266 norm->v_delay, norm->video_v_start,
267 norm->video_v_stop);
268
269 switch (dev->vdecoder) {
270 case TW6800:
271 hdelay = norm->h_delay0;
272 break;
273 default:
274 hdelay = norm->h_delay;
275 break;
276 }
277
278 hdelay += norm->h_start;
279 hactive = norm->h_stop - norm->h_start + 1;
280
281 hscale = (hactive * 256) / (width);
282
283 vdelay = norm->v_delay;
284 vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;
285 vscale = (vactive * 256) / height;
286
287 pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,
288 width, height,
289 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
290 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
291 v4l2_norm_to_name(dev->tvnorm->id));
292 pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; vactive=%d, vdelay=%d, vscale=%d\n",
293 __func__,
294 hactive, hdelay, hscale, vactive, vdelay, vscale);
295
296 comb = ((vdelay & 0x300) >> 2) |
297 ((vactive & 0x300) >> 4) |
298 ((hdelay & 0x300) >> 6) |
299 ((hactive & 0x300) >> 8);
300 pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
301 __func__, comb, vdelay, vactive, hdelay, hactive);
302 tw_writeb(TW68_CROP_HI, comb);
303 tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);
304 tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);
305 tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);
306 tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);
307
308 comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);
309 pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, HSCALE_LO=%02x\n",
310 __func__, comb, vscale, hscale);
311 tw_writeb(TW68_SCALE_HI, comb);
312 tw_writeb(TW68_VSCALE_LO, vscale);
313 tw_writeb(TW68_HSCALE_LO, hscale);
314
315 return 0;
316}
317
318
319
320int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
321{
322
323 tw68_set_scale(dev, dev->width, dev->height, dev->field);
324
325
326
327
328
329 tw_clearl(TW68_DMAC, TW68_DMAP_EN);
330 tw_writel(TW68_DMAP_SA, buf->dma);
331
332 tw_writel(TW68_INTSTAT, dev->board_virqmask);
333
334 tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |
335 ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);
336 dev->pci_irqmask |= dev->board_virqmask;
337 tw_setl(TW68_INTMASK, dev->pci_irqmask);
338 return 0;
339}
340
341
342
343
344
345static int tw68_buffer_count(unsigned int size, unsigned int count)
346{
347 unsigned int maxcount;
348
349 maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);
350 if (count > maxcount)
351 count = maxcount;
352 return count;
353}
354
355
356
357
358static int tw68_queue_setup(struct vb2_queue *q,
359 unsigned int *num_buffers, unsigned int *num_planes,
360 unsigned int sizes[], struct device *alloc_devs[])
361{
362 struct tw68_dev *dev = vb2_get_drv_priv(q);
363 unsigned tot_bufs = q->num_buffers + *num_buffers;
364 unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3;
365
366 if (tot_bufs < 2)
367 tot_bufs = 2;
368 tot_bufs = tw68_buffer_count(size, tot_bufs);
369 *num_buffers = tot_bufs - q->num_buffers;
370
371
372
373
374
375 if (*num_planes)
376 return sizes[0] < size ? -EINVAL : 0;
377 *num_planes = 1;
378 sizes[0] = size;
379
380 return 0;
381}
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403static void tw68_buf_queue(struct vb2_buffer *vb)
404{
405 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
406 struct vb2_queue *vq = vb->vb2_queue;
407 struct tw68_dev *dev = vb2_get_drv_priv(vq);
408 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
409 struct tw68_buf *prev;
410 unsigned long flags;
411
412 spin_lock_irqsave(&dev->slock, flags);
413
414
415 buf->jmp[0] = cpu_to_le32(RISC_JUMP);
416 buf->jmp[1] = cpu_to_le32(buf->dma + 8);
417
418 if (!list_empty(&dev->active)) {
419 prev = list_entry(dev->active.prev, struct tw68_buf, list);
420 buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);
421 prev->jmp[1] = cpu_to_le32(buf->dma);
422 }
423 list_add_tail(&buf->list, &dev->active);
424 spin_unlock_irqrestore(&dev->slock, flags);
425}
426
427
428
429
430
431
432
433
434
435
436
437
438static int tw68_buf_prepare(struct vb2_buffer *vb)
439{
440 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
441 struct vb2_queue *vq = vb->vb2_queue;
442 struct tw68_dev *dev = vb2_get_drv_priv(vq);
443 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
444 struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
445 unsigned size, bpl;
446
447 size = (dev->width * dev->height * dev->fmt->depth) >> 3;
448 if (vb2_plane_size(vb, 0) < size)
449 return -EINVAL;
450 vb2_set_plane_payload(vb, 0, size);
451
452 bpl = (dev->width * dev->fmt->depth) >> 3;
453 switch (dev->field) {
454 case V4L2_FIELD_TOP:
455 tw68_risc_buffer(dev->pci, buf, dma->sgl,
456 0, UNSET, bpl, 0, dev->height);
457 break;
458 case V4L2_FIELD_BOTTOM:
459 tw68_risc_buffer(dev->pci, buf, dma->sgl,
460 UNSET, 0, bpl, 0, dev->height);
461 break;
462 case V4L2_FIELD_SEQ_TB:
463 tw68_risc_buffer(dev->pci, buf, dma->sgl,
464 0, bpl * (dev->height >> 1),
465 bpl, 0, dev->height >> 1);
466 break;
467 case V4L2_FIELD_SEQ_BT:
468 tw68_risc_buffer(dev->pci, buf, dma->sgl,
469 bpl * (dev->height >> 1), 0,
470 bpl, 0, dev->height >> 1);
471 break;
472 case V4L2_FIELD_INTERLACED:
473 default:
474 tw68_risc_buffer(dev->pci, buf, dma->sgl,
475 0, bpl, bpl, bpl, dev->height >> 1);
476 break;
477 }
478 return 0;
479}
480
481static void tw68_buf_finish(struct vb2_buffer *vb)
482{
483 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
484 struct vb2_queue *vq = vb->vb2_queue;
485 struct tw68_dev *dev = vb2_get_drv_priv(vq);
486 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
487
488 pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma);
489}
490
491static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
492{
493 struct tw68_dev *dev = vb2_get_drv_priv(q);
494 struct tw68_buf *buf =
495 container_of(dev->active.next, struct tw68_buf, list);
496
497 dev->seqnr = 0;
498 tw68_video_start_dma(dev, buf);
499 return 0;
500}
501
502static void tw68_stop_streaming(struct vb2_queue *q)
503{
504 struct tw68_dev *dev = vb2_get_drv_priv(q);
505
506
507 tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
508 while (!list_empty(&dev->active)) {
509 struct tw68_buf *buf =
510 container_of(dev->active.next, struct tw68_buf, list);
511
512 list_del(&buf->list);
513 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
514 }
515}
516
517static const struct vb2_ops tw68_video_qops = {
518 .queue_setup = tw68_queue_setup,
519 .buf_queue = tw68_buf_queue,
520 .buf_prepare = tw68_buf_prepare,
521 .buf_finish = tw68_buf_finish,
522 .start_streaming = tw68_start_streaming,
523 .stop_streaming = tw68_stop_streaming,
524 .wait_prepare = vb2_ops_wait_prepare,
525 .wait_finish = vb2_ops_wait_finish,
526};
527
528
529
530static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
531{
532 struct tw68_dev *dev =
533 container_of(ctrl->handler, struct tw68_dev, hdl);
534
535 switch (ctrl->id) {
536 case V4L2_CID_BRIGHTNESS:
537 tw_writeb(TW68_BRIGHT, ctrl->val);
538 break;
539 case V4L2_CID_HUE:
540 tw_writeb(TW68_HUE, ctrl->val);
541 break;
542 case V4L2_CID_CONTRAST:
543 tw_writeb(TW68_CONTRAST, ctrl->val);
544 break;
545 case V4L2_CID_SATURATION:
546 tw_writeb(TW68_SAT_U, ctrl->val);
547 tw_writeb(TW68_SAT_V, ctrl->val);
548 break;
549 case V4L2_CID_COLOR_KILLER:
550 if (ctrl->val)
551 tw_andorb(TW68_MISC2, 0xe0, 0xe0);
552 else
553 tw_andorb(TW68_MISC2, 0xe0, 0x00);
554 break;
555 case V4L2_CID_CHROMA_AGC:
556 if (ctrl->val)
557 tw_andorb(TW68_LOOP, 0x30, 0x20);
558 else
559 tw_andorb(TW68_LOOP, 0x30, 0x00);
560 break;
561 }
562 return 0;
563}
564
565
566
567
568
569
570
571static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
572 struct v4l2_format *f)
573{
574 struct tw68_dev *dev = video_drvdata(file);
575
576 f->fmt.pix.width = dev->width;
577 f->fmt.pix.height = dev->height;
578 f->fmt.pix.field = dev->field;
579 f->fmt.pix.pixelformat = dev->fmt->fourcc;
580 f->fmt.pix.bytesperline =
581 (f->fmt.pix.width * (dev->fmt->depth)) >> 3;
582 f->fmt.pix.sizeimage =
583 f->fmt.pix.height * f->fmt.pix.bytesperline;
584 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
585 return 0;
586}
587
588static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
589 struct v4l2_format *f)
590{
591 struct tw68_dev *dev = video_drvdata(file);
592 const struct tw68_format *fmt;
593 enum v4l2_field field;
594 unsigned int maxh;
595
596 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
597 if (NULL == fmt)
598 return -EINVAL;
599
600 field = f->fmt.pix.field;
601 maxh = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;
602
603 switch (field) {
604 case V4L2_FIELD_TOP:
605 case V4L2_FIELD_BOTTOM:
606 break;
607 case V4L2_FIELD_INTERLACED:
608 case V4L2_FIELD_SEQ_BT:
609 case V4L2_FIELD_SEQ_TB:
610 maxh = maxh * 2;
611 break;
612 default:
613 field = (f->fmt.pix.height > maxh / 2)
614 ? V4L2_FIELD_INTERLACED
615 : V4L2_FIELD_BOTTOM;
616 break;
617 }
618
619 f->fmt.pix.field = field;
620 if (f->fmt.pix.width < 48)
621 f->fmt.pix.width = 48;
622 if (f->fmt.pix.height < 32)
623 f->fmt.pix.height = 32;
624 if (f->fmt.pix.width > 720)
625 f->fmt.pix.width = 720;
626 if (f->fmt.pix.height > maxh)
627 f->fmt.pix.height = maxh;
628 f->fmt.pix.width &= ~0x03;
629 f->fmt.pix.bytesperline =
630 (f->fmt.pix.width * (fmt->depth)) >> 3;
631 f->fmt.pix.sizeimage =
632 f->fmt.pix.height * f->fmt.pix.bytesperline;
633 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
634 return 0;
635}
636
637
638
639
640
641
642
643static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
644 struct v4l2_format *f)
645{
646 struct tw68_dev *dev = video_drvdata(file);
647 int err;
648
649 err = tw68_try_fmt_vid_cap(file, priv, f);
650 if (0 != err)
651 return err;
652
653 dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
654 dev->width = f->fmt.pix.width;
655 dev->height = f->fmt.pix.height;
656 dev->field = f->fmt.pix.field;
657 return 0;
658}
659
660static int tw68_enum_input(struct file *file, void *priv,
661 struct v4l2_input *i)
662{
663 struct tw68_dev *dev = video_drvdata(file);
664 unsigned int n;
665
666 n = i->index;
667 if (n >= TW68_INPUT_MAX)
668 return -EINVAL;
669 i->index = n;
670 i->type = V4L2_INPUT_TYPE_CAMERA;
671 snprintf(i->name, sizeof(i->name), "Composite %d", n);
672
673
674 if (n == dev->input) {
675 int v1 = tw_readb(TW68_STATUS1);
676 int v2 = tw_readb(TW68_MVSN);
677
678 if (0 != (v1 & (1 << 7)))
679 i->status |= V4L2_IN_ST_NO_SYNC;
680 if (0 != (v1 & (1 << 6)))
681 i->status |= V4L2_IN_ST_NO_H_LOCK;
682 if (0 != (v1 & (1 << 2)))
683 i->status |= V4L2_IN_ST_NO_SIGNAL;
684 if (0 != (v1 & 1 << 1))
685 i->status |= V4L2_IN_ST_NO_COLOR;
686 if (0 != (v2 & (1 << 2)))
687 i->status |= V4L2_IN_ST_MACROVISION;
688 }
689 i->std = video_devdata(file)->tvnorms;
690 return 0;
691}
692
693static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
694{
695 struct tw68_dev *dev = video_drvdata(file);
696
697 *i = dev->input;
698 return 0;
699}
700
701static int tw68_s_input(struct file *file, void *priv, unsigned int i)
702{
703 struct tw68_dev *dev = video_drvdata(file);
704
705 if (i >= TW68_INPUT_MAX)
706 return -EINVAL;
707 dev->input = i;
708 tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);
709 return 0;
710}
711
712static int tw68_querycap(struct file *file, void *priv,
713 struct v4l2_capability *cap)
714{
715 struct tw68_dev *dev = video_drvdata(file);
716
717 strscpy(cap->driver, "tw68", sizeof(cap->driver));
718 strscpy(cap->card, "Techwell Capture Card",
719 sizeof(cap->card));
720 sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
721 return 0;
722}
723
724static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
725{
726 struct tw68_dev *dev = video_drvdata(file);
727 unsigned int i;
728
729 if (vb2_is_busy(&dev->vidq))
730 return -EBUSY;
731
732
733 for (i = 0; i < TVNORMS; i++) {
734 if (id == tvnorms[i].id)
735 break;
736 }
737
738
739 if (i == TVNORMS) {
740 for (i = 0; i < TVNORMS; i++)
741 if (id & tvnorms[i].id)
742 break;
743 }
744
745 if (i == TVNORMS)
746 return -EINVAL;
747
748 set_tvnorm(dev, &tvnorms[i]);
749 return 0;
750}
751
752static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
753{
754 struct tw68_dev *dev = video_drvdata(file);
755
756 *id = dev->tvnorm->id;
757 return 0;
758}
759
760static int tw68_enum_fmt_vid_cap(struct file *file, void *priv,
761 struct v4l2_fmtdesc *f)
762{
763 if (f->index >= FORMATS)
764 return -EINVAL;
765
766 f->pixelformat = formats[f->index].fourcc;
767
768 return 0;
769}
770
771
772
773
774
775static void tw68_dump_regs(struct tw68_dev *dev)
776{
777 unsigned char line[80];
778 int i, j, k;
779 unsigned char *cptr;
780
781 pr_info("Full dump of TW68 registers:\n");
782
783 for (i = 0; i < 0x100; i += 32) {
784 cptr = line;
785 cptr += sprintf(cptr, "%03x ", i);
786
787 for (j = i; j < i + 16; j += 4)
788 cptr += sprintf(cptr, "%08x ", tw_readl(j));
789 *cptr++ = ' ';
790 for (; j < i + 32; j += 4)
791 cptr += sprintf(cptr, "%08x ", tw_readl(j));
792 *cptr++ = '\n';
793 *cptr = 0;
794 pr_info("%s", line);
795 }
796
797 while (i < 0x400) {
798 cptr = line;
799 cptr += sprintf(cptr, "%03x ", i);
800
801 for (j = 0; j < 4; j++) {
802 for (k = 0; k < 4; k++) {
803 cptr += sprintf(cptr, "%02x ",
804 tw_readb(i));
805 i += 4;
806 }
807 *cptr++ = ' ';
808 }
809 *cptr++ = '\n';
810 *cptr = 0;
811 pr_info("%s", line);
812 }
813}
814
815static int vidioc_log_status(struct file *file, void *priv)
816{
817 struct tw68_dev *dev = video_drvdata(file);
818
819 tw68_dump_regs(dev);
820 return v4l2_ctrl_log_status(file, priv);
821}
822
823#ifdef CONFIG_VIDEO_ADV_DEBUG
824static int vidioc_g_register(struct file *file, void *priv,
825 struct v4l2_dbg_register *reg)
826{
827 struct tw68_dev *dev = video_drvdata(file);
828
829 if (reg->size == 1)
830 reg->val = tw_readb(reg->reg);
831 else
832 reg->val = tw_readl(reg->reg);
833 return 0;
834}
835
836static int vidioc_s_register(struct file *file, void *priv,
837 const struct v4l2_dbg_register *reg)
838{
839 struct tw68_dev *dev = video_drvdata(file);
840
841 if (reg->size == 1)
842 tw_writeb(reg->reg, reg->val);
843 else
844 tw_writel(reg->reg & 0xffff, reg->val);
845 return 0;
846}
847#endif
848
849static const struct v4l2_ctrl_ops tw68_ctrl_ops = {
850 .s_ctrl = tw68_s_ctrl,
851};
852
853static const struct v4l2_file_operations video_fops = {
854 .owner = THIS_MODULE,
855 .open = v4l2_fh_open,
856 .release = vb2_fop_release,
857 .read = vb2_fop_read,
858 .poll = vb2_fop_poll,
859 .mmap = vb2_fop_mmap,
860 .unlocked_ioctl = video_ioctl2,
861};
862
863static const struct v4l2_ioctl_ops video_ioctl_ops = {
864 .vidioc_querycap = tw68_querycap,
865 .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap,
866 .vidioc_reqbufs = vb2_ioctl_reqbufs,
867 .vidioc_create_bufs = vb2_ioctl_create_bufs,
868 .vidioc_querybuf = vb2_ioctl_querybuf,
869 .vidioc_qbuf = vb2_ioctl_qbuf,
870 .vidioc_dqbuf = vb2_ioctl_dqbuf,
871 .vidioc_s_std = tw68_s_std,
872 .vidioc_g_std = tw68_g_std,
873 .vidioc_enum_input = tw68_enum_input,
874 .vidioc_g_input = tw68_g_input,
875 .vidioc_s_input = tw68_s_input,
876 .vidioc_streamon = vb2_ioctl_streamon,
877 .vidioc_streamoff = vb2_ioctl_streamoff,
878 .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap,
879 .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap,
880 .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap,
881 .vidioc_log_status = vidioc_log_status,
882 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
883 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
884#ifdef CONFIG_VIDEO_ADV_DEBUG
885 .vidioc_g_register = vidioc_g_register,
886 .vidioc_s_register = vidioc_s_register,
887#endif
888};
889
890static const struct video_device tw68_video_template = {
891 .name = "tw68_video",
892 .fops = &video_fops,
893 .ioctl_ops = &video_ioctl_ops,
894 .release = video_device_release_empty,
895 .tvnorms = TW68_NORMS,
896 .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
897 V4L2_CAP_STREAMING,
898};
899
900
901
902void tw68_set_tvnorm_hw(struct tw68_dev *dev)
903{
904 tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);
905}
906
907int tw68_video_init1(struct tw68_dev *dev)
908{
909 struct v4l2_ctrl_handler *hdl = &dev->hdl;
910
911 v4l2_ctrl_handler_init(hdl, 6);
912 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
913 V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);
914 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
915 V4L2_CID_CONTRAST, 0, 255, 1, 100);
916 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
917 V4L2_CID_SATURATION, 0, 255, 1, 128);
918
919 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
920 V4L2_CID_HUE, -128, 127, 1, 0);
921 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
922 V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
923 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
924 V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
925 if (hdl->error) {
926 v4l2_ctrl_handler_free(hdl);
927 return hdl->error;
928 }
929 dev->v4l2_dev.ctrl_handler = hdl;
930 v4l2_ctrl_handler_setup(hdl);
931 return 0;
932}
933
934int tw68_video_init2(struct tw68_dev *dev, int video_nr)
935{
936 int ret;
937
938 set_tvnorm(dev, &tvnorms[0]);
939
940 dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
941 dev->width = 720;
942 dev->height = 576;
943 dev->field = V4L2_FIELD_INTERLACED;
944
945 INIT_LIST_HEAD(&dev->active);
946 dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
947 dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
948 dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
949 dev->vidq.ops = &tw68_video_qops;
950 dev->vidq.mem_ops = &vb2_dma_sg_memops;
951 dev->vidq.drv_priv = dev;
952 dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
953 dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
954 dev->vidq.lock = &dev->lock;
955 dev->vidq.min_buffers_needed = 2;
956 dev->vidq.dev = &dev->pci->dev;
957 ret = vb2_queue_init(&dev->vidq);
958 if (ret)
959 return ret;
960 dev->vdev = tw68_video_template;
961 dev->vdev.v4l2_dev = &dev->v4l2_dev;
962 dev->vdev.lock = &dev->lock;
963 dev->vdev.queue = &dev->vidq;
964 video_set_drvdata(&dev->vdev, dev);
965 return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
966}
967
968
969
970
971void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
972{
973 __u32 reg;
974
975
976 tw_writel(TW68_INTSTAT, status);
977
978
979
980
981
982
983 if (status & TW68_DMAPI) {
984 struct tw68_buf *buf;
985
986 spin_lock(&dev->slock);
987 buf = list_entry(dev->active.next, struct tw68_buf, list);
988 list_del(&buf->list);
989 spin_unlock(&dev->slock);
990 buf->vb.vb2_buf.timestamp = ktime_get_ns();
991 buf->vb.field = dev->field;
992 buf->vb.sequence = dev->seqnr++;
993 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
994 status &= ~(TW68_DMAPI);
995 if (0 == status)
996 return;
997 }
998 if (status & (TW68_VLOCK | TW68_HLOCK))
999 dev_dbg(&dev->pci->dev, "Lost sync\n");
1000 if (status & TW68_PABORT)
1001 dev_err(&dev->pci->dev, "PABORT interrupt\n");
1002 if (status & TW68_DMAPERR)
1003 dev_err(&dev->pci->dev, "DMAPERR interrupt\n");
1004
1005
1006
1007
1008 if (status & TW68_FDMIS)
1009 dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");
1010 if (status & TW68_FFOF) {
1011
1012 reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;
1013 tw_clearl(TW68_DMAC, TW68_FIFO_EN);
1014 dev_dbg(&dev->pci->dev, "FFOF interrupt\n");
1015 tw_setl(TW68_DMAC, reg);
1016 }
1017 if (status & TW68_FFERR)
1018 dev_dbg(&dev->pci->dev, "FFERR interrupt\n");
1019}
1020