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