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