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, v_delay=%d, v_start=%d, v_stop=%d\n",
283 __func__, width, height, V4L2_FIELD_HAS_BOTH(field),
284 norm->h_delay, norm->h_start, norm->h_stop,
285 norm->v_delay, norm->video_v_start,
286 norm->video_v_stop);
287
288 switch (dev->vdecoder) {
289 case TW6800:
290 hdelay = norm->h_delay0;
291 break;
292 default:
293 hdelay = norm->h_delay;
294 break;
295 }
296
297 hdelay += norm->h_start;
298 hactive = norm->h_stop - norm->h_start + 1;
299
300 hscale = (hactive * 256) / (width);
301
302 vdelay = norm->v_delay;
303 vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;
304 vscale = (vactive * 256) / height;
305
306 pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,
307 width, height,
308 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
309 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
310 v4l2_norm_to_name(dev->tvnorm->id));
311 pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; vactive=%d, vdelay=%d, vscale=%d\n",
312 __func__,
313 hactive, hdelay, hscale, vactive, vdelay, vscale);
314
315 comb = ((vdelay & 0x300) >> 2) |
316 ((vactive & 0x300) >> 4) |
317 ((hdelay & 0x300) >> 6) |
318 ((hactive & 0x300) >> 8);
319 pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
320 __func__, comb, vdelay, vactive, hdelay, hactive);
321 tw_writeb(TW68_CROP_HI, comb);
322 tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);
323 tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);
324 tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);
325 tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);
326
327 comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);
328 pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, HSCALE_LO=%02x\n",
329 __func__, comb, vscale, hscale);
330 tw_writeb(TW68_SCALE_HI, comb);
331 tw_writeb(TW68_VSCALE_LO, vscale);
332 tw_writeb(TW68_HSCALE_LO, hscale);
333
334 return 0;
335}
336
337
338
339int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
340{
341
342 tw68_set_scale(dev, dev->width, dev->height, dev->field);
343
344
345
346
347
348 tw_clearl(TW68_DMAC, TW68_DMAP_EN);
349 tw_writel(TW68_DMAP_SA, buf->dma);
350
351 tw_writel(TW68_INTSTAT, dev->board_virqmask);
352
353 tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |
354 ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);
355 dev->pci_irqmask |= dev->board_virqmask;
356 tw_setl(TW68_INTMASK, dev->pci_irqmask);
357 return 0;
358}
359
360
361
362
363
364static int tw68_buffer_count(unsigned int size, unsigned int count)
365{
366 unsigned int maxcount;
367
368 maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);
369 if (count > maxcount)
370 count = maxcount;
371 return count;
372}
373
374
375
376
377static int tw68_queue_setup(struct vb2_queue *q,
378 unsigned int *num_buffers, unsigned int *num_planes,
379 unsigned int sizes[], struct device *alloc_devs[])
380{
381 struct tw68_dev *dev = vb2_get_drv_priv(q);
382 unsigned tot_bufs = q->num_buffers + *num_buffers;
383 unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3;
384
385 if (tot_bufs < 2)
386 tot_bufs = 2;
387 tot_bufs = tw68_buffer_count(size, tot_bufs);
388 *num_buffers = tot_bufs - q->num_buffers;
389
390
391
392
393
394 if (*num_planes)
395 return sizes[0] < size ? -EINVAL : 0;
396 *num_planes = 1;
397 sizes[0] = size;
398
399 return 0;
400}
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422static void tw68_buf_queue(struct vb2_buffer *vb)
423{
424 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
425 struct vb2_queue *vq = vb->vb2_queue;
426 struct tw68_dev *dev = vb2_get_drv_priv(vq);
427 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
428 struct tw68_buf *prev;
429 unsigned long flags;
430
431 spin_lock_irqsave(&dev->slock, flags);
432
433
434 buf->jmp[0] = cpu_to_le32(RISC_JUMP);
435 buf->jmp[1] = cpu_to_le32(buf->dma + 8);
436
437 if (!list_empty(&dev->active)) {
438 prev = list_entry(dev->active.prev, struct tw68_buf, list);
439 buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);
440 prev->jmp[1] = cpu_to_le32(buf->dma);
441 }
442 list_add_tail(&buf->list, &dev->active);
443 spin_unlock_irqrestore(&dev->slock, flags);
444}
445
446
447
448
449
450
451
452
453
454
455
456
457static int tw68_buf_prepare(struct vb2_buffer *vb)
458{
459 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
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(vbuf, 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_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
503 struct vb2_queue *vq = vb->vb2_queue;
504 struct tw68_dev *dev = vb2_get_drv_priv(vq);
505 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
506
507 pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma);
508}
509
510static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
511{
512 struct tw68_dev *dev = vb2_get_drv_priv(q);
513 struct tw68_buf *buf =
514 container_of(dev->active.next, struct tw68_buf, list);
515
516 dev->seqnr = 0;
517 tw68_video_start_dma(dev, buf);
518 return 0;
519}
520
521static void tw68_stop_streaming(struct vb2_queue *q)
522{
523 struct tw68_dev *dev = vb2_get_drv_priv(q);
524
525
526 tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
527 while (!list_empty(&dev->active)) {
528 struct tw68_buf *buf =
529 container_of(dev->active.next, struct tw68_buf, list);
530
531 list_del(&buf->list);
532 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
533 }
534}
535
536static const struct vb2_ops tw68_video_qops = {
537 .queue_setup = tw68_queue_setup,
538 .buf_queue = tw68_buf_queue,
539 .buf_prepare = tw68_buf_prepare,
540 .buf_finish = tw68_buf_finish,
541 .start_streaming = tw68_start_streaming,
542 .stop_streaming = tw68_stop_streaming,
543 .wait_prepare = vb2_ops_wait_prepare,
544 .wait_finish = vb2_ops_wait_finish,
545};
546
547
548
549static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
550{
551 struct tw68_dev *dev =
552 container_of(ctrl->handler, struct tw68_dev, hdl);
553
554 switch (ctrl->id) {
555 case V4L2_CID_BRIGHTNESS:
556 tw_writeb(TW68_BRIGHT, ctrl->val);
557 break;
558 case V4L2_CID_HUE:
559 tw_writeb(TW68_HUE, ctrl->val);
560 break;
561 case V4L2_CID_CONTRAST:
562 tw_writeb(TW68_CONTRAST, ctrl->val);
563 break;
564 case V4L2_CID_SATURATION:
565 tw_writeb(TW68_SAT_U, ctrl->val);
566 tw_writeb(TW68_SAT_V, ctrl->val);
567 break;
568 case V4L2_CID_COLOR_KILLER:
569 if (ctrl->val)
570 tw_andorb(TW68_MISC2, 0xe0, 0xe0);
571 else
572 tw_andorb(TW68_MISC2, 0xe0, 0x00);
573 break;
574 case V4L2_CID_CHROMA_AGC:
575 if (ctrl->val)
576 tw_andorb(TW68_LOOP, 0x30, 0x20);
577 else
578 tw_andorb(TW68_LOOP, 0x30, 0x00);
579 break;
580 }
581 return 0;
582}
583
584
585
586
587
588
589
590static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
591 struct v4l2_format *f)
592{
593 struct tw68_dev *dev = video_drvdata(file);
594
595 f->fmt.pix.width = dev->width;
596 f->fmt.pix.height = dev->height;
597 f->fmt.pix.field = dev->field;
598 f->fmt.pix.pixelformat = dev->fmt->fourcc;
599 f->fmt.pix.bytesperline =
600 (f->fmt.pix.width * (dev->fmt->depth)) >> 3;
601 f->fmt.pix.sizeimage =
602 f->fmt.pix.height * f->fmt.pix.bytesperline;
603 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
604 f->fmt.pix.priv = 0;
605 return 0;
606}
607
608static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
609 struct v4l2_format *f)
610{
611 struct tw68_dev *dev = video_drvdata(file);
612 const struct tw68_format *fmt;
613 enum v4l2_field field;
614 unsigned int maxh;
615
616 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
617 if (NULL == fmt)
618 return -EINVAL;
619
620 field = f->fmt.pix.field;
621 maxh = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;
622
623 switch (field) {
624 case V4L2_FIELD_TOP:
625 case V4L2_FIELD_BOTTOM:
626 break;
627 case V4L2_FIELD_INTERLACED:
628 case V4L2_FIELD_SEQ_BT:
629 case V4L2_FIELD_SEQ_TB:
630 maxh = maxh * 2;
631 break;
632 default:
633 field = (f->fmt.pix.height > maxh / 2)
634 ? V4L2_FIELD_INTERLACED
635 : V4L2_FIELD_BOTTOM;
636 break;
637 }
638
639 f->fmt.pix.field = field;
640 if (f->fmt.pix.width < 48)
641 f->fmt.pix.width = 48;
642 if (f->fmt.pix.height < 32)
643 f->fmt.pix.height = 32;
644 if (f->fmt.pix.width > 720)
645 f->fmt.pix.width = 720;
646 if (f->fmt.pix.height > maxh)
647 f->fmt.pix.height = maxh;
648 f->fmt.pix.width &= ~0x03;
649 f->fmt.pix.bytesperline =
650 (f->fmt.pix.width * (fmt->depth)) >> 3;
651 f->fmt.pix.sizeimage =
652 f->fmt.pix.height * f->fmt.pix.bytesperline;
653 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
654 return 0;
655}
656
657
658
659
660
661
662
663static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
664 struct v4l2_format *f)
665{
666 struct tw68_dev *dev = video_drvdata(file);
667 int err;
668
669 err = tw68_try_fmt_vid_cap(file, priv, f);
670 if (0 != err)
671 return err;
672
673 dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
674 dev->width = f->fmt.pix.width;
675 dev->height = f->fmt.pix.height;
676 dev->field = f->fmt.pix.field;
677 return 0;
678}
679
680static int tw68_enum_input(struct file *file, void *priv,
681 struct v4l2_input *i)
682{
683 struct tw68_dev *dev = video_drvdata(file);
684 unsigned int n;
685
686 n = i->index;
687 if (n >= TW68_INPUT_MAX)
688 return -EINVAL;
689 i->index = n;
690 i->type = V4L2_INPUT_TYPE_CAMERA;
691 snprintf(i->name, sizeof(i->name), "Composite %d", n);
692
693
694 if (n == dev->input) {
695 int v1 = tw_readb(TW68_STATUS1);
696 int v2 = tw_readb(TW68_MVSN);
697
698 if (0 != (v1 & (1 << 7)))
699 i->status |= V4L2_IN_ST_NO_SYNC;
700 if (0 != (v1 & (1 << 6)))
701 i->status |= V4L2_IN_ST_NO_H_LOCK;
702 if (0 != (v1 & (1 << 2)))
703 i->status |= V4L2_IN_ST_NO_SIGNAL;
704 if (0 != (v1 & 1 << 1))
705 i->status |= V4L2_IN_ST_NO_COLOR;
706 if (0 != (v2 & (1 << 2)))
707 i->status |= V4L2_IN_ST_MACROVISION;
708 }
709 i->std = video_devdata(file)->tvnorms;
710 return 0;
711}
712
713static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
714{
715 struct tw68_dev *dev = video_drvdata(file);
716
717 *i = dev->input;
718 return 0;
719}
720
721static int tw68_s_input(struct file *file, void *priv, unsigned int i)
722{
723 struct tw68_dev *dev = video_drvdata(file);
724
725 if (i >= TW68_INPUT_MAX)
726 return -EINVAL;
727 dev->input = i;
728 tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);
729 return 0;
730}
731
732static int tw68_querycap(struct file *file, void *priv,
733 struct v4l2_capability *cap)
734{
735 struct tw68_dev *dev = video_drvdata(file);
736
737 strcpy(cap->driver, "tw68");
738 strlcpy(cap->card, "Techwell Capture Card",
739 sizeof(cap->card));
740 sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
741 cap->device_caps =
742 V4L2_CAP_VIDEO_CAPTURE |
743 V4L2_CAP_READWRITE |
744 V4L2_CAP_STREAMING;
745
746 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
747 return 0;
748}
749
750static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
751{
752 struct tw68_dev *dev = video_drvdata(file);
753 unsigned int i;
754
755 if (vb2_is_busy(&dev->vidq))
756 return -EBUSY;
757
758
759 for (i = 0; i < TVNORMS; i++) {
760 if (id == tvnorms[i].id)
761 break;
762 }
763
764
765 if (i == TVNORMS) {
766 for (i = 0; i < TVNORMS; i++)
767 if (id & tvnorms[i].id)
768 break;
769 }
770
771 if (i == TVNORMS)
772 return -EINVAL;
773
774 set_tvnorm(dev, &tvnorms[i]);
775 return 0;
776}
777
778static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
779{
780 struct tw68_dev *dev = video_drvdata(file);
781
782 *id = dev->tvnorm->id;
783 return 0;
784}
785
786static int tw68_enum_fmt_vid_cap(struct file *file, void *priv,
787 struct v4l2_fmtdesc *f)
788{
789 if (f->index >= FORMATS)
790 return -EINVAL;
791
792 strlcpy(f->description, formats[f->index].name,
793 sizeof(f->description));
794
795 f->pixelformat = formats[f->index].fourcc;
796
797 return 0;
798}
799
800
801
802
803
804static void tw68_dump_regs(struct tw68_dev *dev)
805{
806 unsigned char line[80];
807 int i, j, k;
808 unsigned char *cptr;
809
810 pr_info("Full dump of TW68 registers:\n");
811
812 for (i = 0; i < 0x100; i += 32) {
813 cptr = line;
814 cptr += sprintf(cptr, "%03x ", i);
815
816 for (j = i; j < i + 16; j += 4)
817 cptr += sprintf(cptr, "%08x ", tw_readl(j));
818 *cptr++ = ' ';
819 for (; j < i + 32; j += 4)
820 cptr += sprintf(cptr, "%08x ", tw_readl(j));
821 *cptr++ = '\n';
822 *cptr = 0;
823 pr_info("%s", line);
824 }
825
826 while (i < 0x400) {
827 cptr = line;
828 cptr += sprintf(cptr, "%03x ", i);
829
830 for (j = 0; j < 4; j++) {
831 for (k = 0; k < 4; k++) {
832 cptr += sprintf(cptr, "%02x ",
833 tw_readb(i));
834 i += 4;
835 }
836 *cptr++ = ' ';
837 }
838 *cptr++ = '\n';
839 *cptr = 0;
840 pr_info("%s", line);
841 }
842}
843
844static int vidioc_log_status(struct file *file, void *priv)
845{
846 struct tw68_dev *dev = video_drvdata(file);
847
848 tw68_dump_regs(dev);
849 return v4l2_ctrl_log_status(file, priv);
850}
851
852#ifdef CONFIG_VIDEO_ADV_DEBUG
853static int vidioc_g_register(struct file *file, void *priv,
854 struct v4l2_dbg_register *reg)
855{
856 struct tw68_dev *dev = video_drvdata(file);
857
858 if (reg->size == 1)
859 reg->val = tw_readb(reg->reg);
860 else
861 reg->val = tw_readl(reg->reg);
862 return 0;
863}
864
865static int vidioc_s_register(struct file *file, void *priv,
866 const struct v4l2_dbg_register *reg)
867{
868 struct tw68_dev *dev = video_drvdata(file);
869
870 if (reg->size == 1)
871 tw_writeb(reg->reg, reg->val);
872 else
873 tw_writel(reg->reg & 0xffff, reg->val);
874 return 0;
875}
876#endif
877
878static const struct v4l2_ctrl_ops tw68_ctrl_ops = {
879 .s_ctrl = tw68_s_ctrl,
880};
881
882static const struct v4l2_file_operations video_fops = {
883 .owner = THIS_MODULE,
884 .open = v4l2_fh_open,
885 .release = vb2_fop_release,
886 .read = vb2_fop_read,
887 .poll = vb2_fop_poll,
888 .mmap = vb2_fop_mmap,
889 .unlocked_ioctl = video_ioctl2,
890};
891
892static const struct v4l2_ioctl_ops video_ioctl_ops = {
893 .vidioc_querycap = tw68_querycap,
894 .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap,
895 .vidioc_reqbufs = vb2_ioctl_reqbufs,
896 .vidioc_create_bufs = vb2_ioctl_create_bufs,
897 .vidioc_querybuf = vb2_ioctl_querybuf,
898 .vidioc_qbuf = vb2_ioctl_qbuf,
899 .vidioc_dqbuf = vb2_ioctl_dqbuf,
900 .vidioc_s_std = tw68_s_std,
901 .vidioc_g_std = tw68_g_std,
902 .vidioc_enum_input = tw68_enum_input,
903 .vidioc_g_input = tw68_g_input,
904 .vidioc_s_input = tw68_s_input,
905 .vidioc_streamon = vb2_ioctl_streamon,
906 .vidioc_streamoff = vb2_ioctl_streamoff,
907 .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap,
908 .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap,
909 .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap,
910 .vidioc_log_status = vidioc_log_status,
911 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
912 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
913#ifdef CONFIG_VIDEO_ADV_DEBUG
914 .vidioc_g_register = vidioc_g_register,
915 .vidioc_s_register = vidioc_s_register,
916#endif
917};
918
919static const struct video_device tw68_video_template = {
920 .name = "tw68_video",
921 .fops = &video_fops,
922 .ioctl_ops = &video_ioctl_ops,
923 .release = video_device_release_empty,
924 .tvnorms = TW68_NORMS,
925};
926
927
928
929void tw68_set_tvnorm_hw(struct tw68_dev *dev)
930{
931 tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);
932}
933
934int tw68_video_init1(struct tw68_dev *dev)
935{
936 struct v4l2_ctrl_handler *hdl = &dev->hdl;
937
938 v4l2_ctrl_handler_init(hdl, 6);
939 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
940 V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);
941 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
942 V4L2_CID_CONTRAST, 0, 255, 1, 100);
943 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
944 V4L2_CID_SATURATION, 0, 255, 1, 128);
945
946 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
947 V4L2_CID_HUE, -128, 127, 1, 0);
948 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
949 V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
950 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
951 V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
952 if (hdl->error) {
953 v4l2_ctrl_handler_free(hdl);
954 return hdl->error;
955 }
956 dev->v4l2_dev.ctrl_handler = hdl;
957 v4l2_ctrl_handler_setup(hdl);
958 return 0;
959}
960
961int tw68_video_init2(struct tw68_dev *dev, int video_nr)
962{
963 int ret;
964
965 set_tvnorm(dev, &tvnorms[0]);
966
967 dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
968 dev->width = 720;
969 dev->height = 576;
970 dev->field = V4L2_FIELD_INTERLACED;
971
972 INIT_LIST_HEAD(&dev->active);
973 dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
974 dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
975 dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
976 dev->vidq.ops = &tw68_video_qops;
977 dev->vidq.mem_ops = &vb2_dma_sg_memops;
978 dev->vidq.drv_priv = dev;
979 dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
980 dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
981 dev->vidq.lock = &dev->lock;
982 dev->vidq.min_buffers_needed = 2;
983 dev->vidq.dev = &dev->pci->dev;
984 ret = vb2_queue_init(&dev->vidq);
985 if (ret)
986 return ret;
987 dev->vdev = tw68_video_template;
988 dev->vdev.v4l2_dev = &dev->v4l2_dev;
989 dev->vdev.lock = &dev->lock;
990 dev->vdev.queue = &dev->vidq;
991 video_set_drvdata(&dev->vdev, dev);
992 return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
993}
994
995
996
997
998void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
999{
1000 __u32 reg;
1001
1002
1003 tw_writel(TW68_INTSTAT, status);
1004
1005
1006
1007
1008
1009
1010 if (status & TW68_DMAPI) {
1011 struct tw68_buf *buf;
1012
1013 spin_lock(&dev->slock);
1014 buf = list_entry(dev->active.next, struct tw68_buf, list);
1015 list_del(&buf->list);
1016 spin_unlock(&dev->slock);
1017 buf->vb.vb2_buf.timestamp = ktime_get_ns();
1018 buf->vb.field = dev->field;
1019 buf->vb.sequence = dev->seqnr++;
1020 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
1021 status &= ~(TW68_DMAPI);
1022 if (0 == status)
1023 return;
1024 }
1025 if (status & (TW68_VLOCK | TW68_HLOCK))
1026 dev_dbg(&dev->pci->dev, "Lost sync\n");
1027 if (status & TW68_PABORT)
1028 dev_err(&dev->pci->dev, "PABORT interrupt\n");
1029 if (status & TW68_DMAPERR)
1030 dev_err(&dev->pci->dev, "DMAPERR interrupt\n");
1031
1032
1033
1034
1035 if (status & TW68_FDMIS)
1036 dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");
1037 if (status & TW68_FFOF) {
1038
1039 reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;
1040 tw_clearl(TW68_DMAC, TW68_FIFO_EN);
1041 dev_dbg(&dev->pci->dev, "FFOF interrupt\n");
1042 tw_setl(TW68_DMAC, reg);
1043 }
1044 if (status & TW68_FFERR)
1045 dev_dbg(&dev->pci->dev, "FFERR interrupt\n");
1046}
1047