0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/module.h>
0020 #include <media/v4l2-common.h>
0021 #include <media/v4l2-event.h>
0022 #include <media/videobuf2-dma-sg.h>
0023
0024 #include "tw68.h"
0025 #include "tw68-reg.h"
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 static const struct tw68_format formats[] = {
0036 {
0037 .fourcc = V4L2_PIX_FMT_RGB555,
0038 .depth = 16,
0039 .twformat = ColorFormatRGB15,
0040 }, {
0041 .fourcc = V4L2_PIX_FMT_RGB555X,
0042 .depth = 16,
0043 .twformat = ColorFormatRGB15 | ColorFormatBSWAP,
0044 }, {
0045 .fourcc = V4L2_PIX_FMT_RGB565,
0046 .depth = 16,
0047 .twformat = ColorFormatRGB16,
0048 }, {
0049 .fourcc = V4L2_PIX_FMT_RGB565X,
0050 .depth = 16,
0051 .twformat = ColorFormatRGB16 | ColorFormatBSWAP,
0052 }, {
0053 .fourcc = V4L2_PIX_FMT_BGR24,
0054 .depth = 24,
0055 .twformat = ColorFormatRGB24,
0056 }, {
0057 .fourcc = V4L2_PIX_FMT_RGB24,
0058 .depth = 24,
0059 .twformat = ColorFormatRGB24 | ColorFormatBSWAP,
0060 }, {
0061 .fourcc = V4L2_PIX_FMT_BGR32,
0062 .depth = 32,
0063 .twformat = ColorFormatRGB32,
0064 }, {
0065 .fourcc = V4L2_PIX_FMT_RGB32,
0066 .depth = 32,
0067 .twformat = ColorFormatRGB32 | ColorFormatBSWAP |
0068 ColorFormatWSWAP,
0069 }, {
0070 .fourcc = V4L2_PIX_FMT_YUYV,
0071 .depth = 16,
0072 .twformat = ColorFormatYUY2,
0073 }, {
0074 .fourcc = V4L2_PIX_FMT_UYVY,
0075 .depth = 16,
0076 .twformat = ColorFormatYUY2 | ColorFormatBSWAP,
0077 }
0078 };
0079 #define FORMATS ARRAY_SIZE(formats)
0080
0081 #define NORM_625_50 \
0082 .h_delay = 3, \
0083 .h_delay0 = 133, \
0084 .h_start = 0, \
0085 .h_stop = 719, \
0086 .v_delay = 24, \
0087 .vbi_v_start_0 = 7, \
0088 .vbi_v_stop_0 = 22, \
0089 .video_v_start = 24, \
0090 .video_v_stop = 311, \
0091 .vbi_v_start_1 = 319
0092
0093 #define NORM_525_60 \
0094 .h_delay = 8, \
0095 .h_delay0 = 138, \
0096 .h_start = 0, \
0097 .h_stop = 719, \
0098 .v_delay = 22, \
0099 .vbi_v_start_0 = 10, \
0100 .vbi_v_stop_0 = 21, \
0101 .video_v_start = 22, \
0102 .video_v_stop = 262, \
0103 .vbi_v_start_1 = 273
0104
0105
0106
0107
0108
0109
0110 static const struct tw68_tvnorm tvnorms[] = {
0111 {
0112 .name = "PAL",
0113 .id = V4L2_STD_PAL,
0114 NORM_625_50,
0115
0116 .sync_control = 0x18,
0117 .luma_control = 0x40,
0118 .chroma_ctrl1 = 0x81,
0119 .chroma_gain = 0x2a,
0120 .chroma_ctrl2 = 0x06,
0121 .vgate_misc = 0x1c,
0122 .format = VideoFormatPALBDGHI,
0123 }, {
0124 .name = "NTSC",
0125 .id = V4L2_STD_NTSC,
0126 NORM_525_60,
0127
0128 .sync_control = 0x59,
0129 .luma_control = 0x40,
0130 .chroma_ctrl1 = 0x89,
0131 .chroma_gain = 0x2a,
0132 .chroma_ctrl2 = 0x0e,
0133 .vgate_misc = 0x18,
0134 .format = VideoFormatNTSC,
0135 }, {
0136 .name = "SECAM",
0137 .id = V4L2_STD_SECAM,
0138 NORM_625_50,
0139
0140 .sync_control = 0x18,
0141 .luma_control = 0x1b,
0142 .chroma_ctrl1 = 0xd1,
0143 .chroma_gain = 0x80,
0144 .chroma_ctrl2 = 0x00,
0145 .vgate_misc = 0x1c,
0146 .format = VideoFormatSECAM,
0147 }, {
0148 .name = "PAL-M",
0149 .id = V4L2_STD_PAL_M,
0150 NORM_525_60,
0151
0152 .sync_control = 0x59,
0153 .luma_control = 0x40,
0154 .chroma_ctrl1 = 0xb9,
0155 .chroma_gain = 0x2a,
0156 .chroma_ctrl2 = 0x0e,
0157 .vgate_misc = 0x18,
0158 .format = VideoFormatPALM,
0159 }, {
0160 .name = "PAL-Nc",
0161 .id = V4L2_STD_PAL_Nc,
0162 NORM_625_50,
0163
0164 .sync_control = 0x18,
0165 .luma_control = 0x40,
0166 .chroma_ctrl1 = 0xa1,
0167 .chroma_gain = 0x2a,
0168 .chroma_ctrl2 = 0x06,
0169 .vgate_misc = 0x1c,
0170 .format = VideoFormatPALNC,
0171 }, {
0172 .name = "PAL-60",
0173 .id = V4L2_STD_PAL_60,
0174 .h_delay = 186,
0175 .h_start = 0,
0176 .h_stop = 719,
0177 .v_delay = 26,
0178 .video_v_start = 23,
0179 .video_v_stop = 262,
0180 .vbi_v_start_0 = 10,
0181 .vbi_v_stop_0 = 21,
0182 .vbi_v_start_1 = 273,
0183
0184 .sync_control = 0x18,
0185 .luma_control = 0x40,
0186 .chroma_ctrl1 = 0x81,
0187 .chroma_gain = 0x2a,
0188 .chroma_ctrl2 = 0x06,
0189 .vgate_misc = 0x1c,
0190 .format = VideoFormatPAL60,
0191 }
0192 };
0193 #define TVNORMS ARRAY_SIZE(tvnorms)
0194
0195 static const struct tw68_format *format_by_fourcc(unsigned int fourcc)
0196 {
0197 unsigned int i;
0198
0199 for (i = 0; i < FORMATS; i++)
0200 if (formats[i].fourcc == fourcc)
0201 return formats+i;
0202 return NULL;
0203 }
0204
0205
0206
0207
0208
0209
0210
0211 static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)
0212 {
0213 if (norm != dev->tvnorm) {
0214 dev->width = 720;
0215 dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576;
0216 dev->tvnorm = norm;
0217 tw68_set_tvnorm_hw(dev);
0218 }
0219 }
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,
0251 unsigned int height, enum v4l2_field field)
0252 {
0253 const struct tw68_tvnorm *norm = dev->tvnorm;
0254
0255 int hactive, hdelay, hscale;
0256 int vactive, vdelay, vscale;
0257 int comb;
0258
0259 if (V4L2_FIELD_HAS_BOTH(field))
0260 height /= 2;
0261
0262 pr_debug("%s: width=%d, height=%d, both=%d\n"
0263 " tvnorm h_delay=%d, h_start=%d, h_stop=%d, v_delay=%d, v_start=%d, v_stop=%d\n",
0264 __func__, width, height, V4L2_FIELD_HAS_BOTH(field),
0265 norm->h_delay, norm->h_start, norm->h_stop,
0266 norm->v_delay, norm->video_v_start,
0267 norm->video_v_stop);
0268
0269 switch (dev->vdecoder) {
0270 case TW6800:
0271 hdelay = norm->h_delay0;
0272 break;
0273 default:
0274 hdelay = norm->h_delay;
0275 break;
0276 }
0277
0278 hdelay += norm->h_start;
0279 hactive = norm->h_stop - norm->h_start + 1;
0280
0281 hscale = (hactive * 256) / (width);
0282
0283 vdelay = norm->v_delay;
0284 vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;
0285 vscale = (vactive * 256) / height;
0286
0287 pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,
0288 width, height,
0289 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
0290 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
0291 v4l2_norm_to_name(dev->tvnorm->id));
0292 pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; vactive=%d, vdelay=%d, vscale=%d\n",
0293 __func__,
0294 hactive, hdelay, hscale, vactive, vdelay, vscale);
0295
0296 comb = ((vdelay & 0x300) >> 2) |
0297 ((vactive & 0x300) >> 4) |
0298 ((hdelay & 0x300) >> 6) |
0299 ((hactive & 0x300) >> 8);
0300 pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
0301 __func__, comb, vdelay, vactive, hdelay, hactive);
0302 tw_writeb(TW68_CROP_HI, comb);
0303 tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);
0304 tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);
0305 tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);
0306 tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);
0307
0308 comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);
0309 pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, HSCALE_LO=%02x\n",
0310 __func__, comb, vscale, hscale);
0311 tw_writeb(TW68_SCALE_HI, comb);
0312 tw_writeb(TW68_VSCALE_LO, vscale);
0313 tw_writeb(TW68_HSCALE_LO, hscale);
0314
0315 return 0;
0316 }
0317
0318
0319
0320 int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
0321 {
0322
0323 tw68_set_scale(dev, dev->width, dev->height, dev->field);
0324
0325
0326
0327
0328
0329 tw_clearl(TW68_DMAC, TW68_DMAP_EN);
0330 tw_writel(TW68_DMAP_SA, buf->dma);
0331
0332 tw_writel(TW68_INTSTAT, dev->board_virqmask);
0333
0334 tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |
0335 ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);
0336 dev->pci_irqmask |= dev->board_virqmask;
0337 tw_setl(TW68_INTMASK, dev->pci_irqmask);
0338 return 0;
0339 }
0340
0341
0342
0343
0344
0345 static int tw68_buffer_count(unsigned int size, unsigned int count)
0346 {
0347 unsigned int maxcount;
0348
0349 maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);
0350 if (count > maxcount)
0351 count = maxcount;
0352 return count;
0353 }
0354
0355
0356
0357
0358 static int tw68_queue_setup(struct vb2_queue *q,
0359 unsigned int *num_buffers, unsigned int *num_planes,
0360 unsigned int sizes[], struct device *alloc_devs[])
0361 {
0362 struct tw68_dev *dev = vb2_get_drv_priv(q);
0363 unsigned tot_bufs = q->num_buffers + *num_buffers;
0364 unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3;
0365
0366 if (tot_bufs < 2)
0367 tot_bufs = 2;
0368 tot_bufs = tw68_buffer_count(size, tot_bufs);
0369 *num_buffers = tot_bufs - q->num_buffers;
0370
0371
0372
0373
0374
0375 if (*num_planes)
0376 return sizes[0] < size ? -EINVAL : 0;
0377 *num_planes = 1;
0378 sizes[0] = size;
0379
0380 return 0;
0381 }
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 static void tw68_buf_queue(struct vb2_buffer *vb)
0404 {
0405 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0406 struct vb2_queue *vq = vb->vb2_queue;
0407 struct tw68_dev *dev = vb2_get_drv_priv(vq);
0408 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
0409 struct tw68_buf *prev;
0410 unsigned long flags;
0411
0412 spin_lock_irqsave(&dev->slock, flags);
0413
0414
0415 buf->jmp[0] = cpu_to_le32(RISC_JUMP);
0416 buf->jmp[1] = cpu_to_le32(buf->dma + 8);
0417
0418 if (!list_empty(&dev->active)) {
0419 prev = list_entry(dev->active.prev, struct tw68_buf, list);
0420 buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);
0421 prev->jmp[1] = cpu_to_le32(buf->dma);
0422 }
0423 list_add_tail(&buf->list, &dev->active);
0424 spin_unlock_irqrestore(&dev->slock, flags);
0425 }
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438 static int tw68_buf_prepare(struct vb2_buffer *vb)
0439 {
0440 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0441 struct vb2_queue *vq = vb->vb2_queue;
0442 struct tw68_dev *dev = vb2_get_drv_priv(vq);
0443 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
0444 struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
0445 unsigned size, bpl;
0446
0447 size = (dev->width * dev->height * dev->fmt->depth) >> 3;
0448 if (vb2_plane_size(vb, 0) < size)
0449 return -EINVAL;
0450 vb2_set_plane_payload(vb, 0, size);
0451
0452 bpl = (dev->width * dev->fmt->depth) >> 3;
0453 switch (dev->field) {
0454 case V4L2_FIELD_TOP:
0455 tw68_risc_buffer(dev->pci, buf, dma->sgl,
0456 0, UNSET, bpl, 0, dev->height);
0457 break;
0458 case V4L2_FIELD_BOTTOM:
0459 tw68_risc_buffer(dev->pci, buf, dma->sgl,
0460 UNSET, 0, bpl, 0, dev->height);
0461 break;
0462 case V4L2_FIELD_SEQ_TB:
0463 tw68_risc_buffer(dev->pci, buf, dma->sgl,
0464 0, bpl * (dev->height >> 1),
0465 bpl, 0, dev->height >> 1);
0466 break;
0467 case V4L2_FIELD_SEQ_BT:
0468 tw68_risc_buffer(dev->pci, buf, dma->sgl,
0469 bpl * (dev->height >> 1), 0,
0470 bpl, 0, dev->height >> 1);
0471 break;
0472 case V4L2_FIELD_INTERLACED:
0473 default:
0474 tw68_risc_buffer(dev->pci, buf, dma->sgl,
0475 0, bpl, bpl, bpl, dev->height >> 1);
0476 break;
0477 }
0478 return 0;
0479 }
0480
0481 static void tw68_buf_finish(struct vb2_buffer *vb)
0482 {
0483 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0484 struct vb2_queue *vq = vb->vb2_queue;
0485 struct tw68_dev *dev = vb2_get_drv_priv(vq);
0486 struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
0487
0488 dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma);
0489 }
0490
0491 static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
0492 {
0493 struct tw68_dev *dev = vb2_get_drv_priv(q);
0494 struct tw68_buf *buf =
0495 container_of(dev->active.next, struct tw68_buf, list);
0496
0497 dev->seqnr = 0;
0498 tw68_video_start_dma(dev, buf);
0499 return 0;
0500 }
0501
0502 static void tw68_stop_streaming(struct vb2_queue *q)
0503 {
0504 struct tw68_dev *dev = vb2_get_drv_priv(q);
0505
0506
0507 tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
0508 while (!list_empty(&dev->active)) {
0509 struct tw68_buf *buf =
0510 container_of(dev->active.next, struct tw68_buf, list);
0511
0512 list_del(&buf->list);
0513 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
0514 }
0515 }
0516
0517 static const struct vb2_ops tw68_video_qops = {
0518 .queue_setup = tw68_queue_setup,
0519 .buf_queue = tw68_buf_queue,
0520 .buf_prepare = tw68_buf_prepare,
0521 .buf_finish = tw68_buf_finish,
0522 .start_streaming = tw68_start_streaming,
0523 .stop_streaming = tw68_stop_streaming,
0524 .wait_prepare = vb2_ops_wait_prepare,
0525 .wait_finish = vb2_ops_wait_finish,
0526 };
0527
0528
0529
0530 static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
0531 {
0532 struct tw68_dev *dev =
0533 container_of(ctrl->handler, struct tw68_dev, hdl);
0534
0535 switch (ctrl->id) {
0536 case V4L2_CID_BRIGHTNESS:
0537 tw_writeb(TW68_BRIGHT, ctrl->val);
0538 break;
0539 case V4L2_CID_HUE:
0540 tw_writeb(TW68_HUE, ctrl->val);
0541 break;
0542 case V4L2_CID_CONTRAST:
0543 tw_writeb(TW68_CONTRAST, ctrl->val);
0544 break;
0545 case V4L2_CID_SATURATION:
0546 tw_writeb(TW68_SAT_U, ctrl->val);
0547 tw_writeb(TW68_SAT_V, ctrl->val);
0548 break;
0549 case V4L2_CID_COLOR_KILLER:
0550 if (ctrl->val)
0551 tw_andorb(TW68_MISC2, 0xe0, 0xe0);
0552 else
0553 tw_andorb(TW68_MISC2, 0xe0, 0x00);
0554 break;
0555 case V4L2_CID_CHROMA_AGC:
0556 if (ctrl->val)
0557 tw_andorb(TW68_LOOP, 0x30, 0x20);
0558 else
0559 tw_andorb(TW68_LOOP, 0x30, 0x00);
0560 break;
0561 }
0562 return 0;
0563 }
0564
0565
0566
0567
0568
0569
0570
0571 static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
0572 struct v4l2_format *f)
0573 {
0574 struct tw68_dev *dev = video_drvdata(file);
0575
0576 f->fmt.pix.width = dev->width;
0577 f->fmt.pix.height = dev->height;
0578 f->fmt.pix.field = dev->field;
0579 f->fmt.pix.pixelformat = dev->fmt->fourcc;
0580 f->fmt.pix.bytesperline =
0581 (f->fmt.pix.width * (dev->fmt->depth)) >> 3;
0582 f->fmt.pix.sizeimage =
0583 f->fmt.pix.height * f->fmt.pix.bytesperline;
0584 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
0585 return 0;
0586 }
0587
0588 static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
0589 struct v4l2_format *f)
0590 {
0591 struct tw68_dev *dev = video_drvdata(file);
0592 const struct tw68_format *fmt;
0593 enum v4l2_field field;
0594 unsigned int maxh;
0595
0596 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
0597 if (NULL == fmt)
0598 return -EINVAL;
0599
0600 field = f->fmt.pix.field;
0601 maxh = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;
0602
0603 switch (field) {
0604 case V4L2_FIELD_TOP:
0605 case V4L2_FIELD_BOTTOM:
0606 break;
0607 case V4L2_FIELD_INTERLACED:
0608 case V4L2_FIELD_SEQ_BT:
0609 case V4L2_FIELD_SEQ_TB:
0610 maxh = maxh * 2;
0611 break;
0612 default:
0613 field = (f->fmt.pix.height > maxh / 2)
0614 ? V4L2_FIELD_INTERLACED
0615 : V4L2_FIELD_BOTTOM;
0616 break;
0617 }
0618
0619 f->fmt.pix.field = field;
0620 if (f->fmt.pix.width < 48)
0621 f->fmt.pix.width = 48;
0622 if (f->fmt.pix.height < 32)
0623 f->fmt.pix.height = 32;
0624 if (f->fmt.pix.width > 720)
0625 f->fmt.pix.width = 720;
0626 if (f->fmt.pix.height > maxh)
0627 f->fmt.pix.height = maxh;
0628 f->fmt.pix.width &= ~0x03;
0629 f->fmt.pix.bytesperline =
0630 (f->fmt.pix.width * (fmt->depth)) >> 3;
0631 f->fmt.pix.sizeimage =
0632 f->fmt.pix.height * f->fmt.pix.bytesperline;
0633 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
0634 return 0;
0635 }
0636
0637
0638
0639
0640
0641
0642
0643 static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
0644 struct v4l2_format *f)
0645 {
0646 struct tw68_dev *dev = video_drvdata(file);
0647 int err;
0648
0649 err = tw68_try_fmt_vid_cap(file, priv, f);
0650 if (0 != err)
0651 return err;
0652
0653 dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
0654 dev->width = f->fmt.pix.width;
0655 dev->height = f->fmt.pix.height;
0656 dev->field = f->fmt.pix.field;
0657 return 0;
0658 }
0659
0660 static int tw68_enum_input(struct file *file, void *priv,
0661 struct v4l2_input *i)
0662 {
0663 struct tw68_dev *dev = video_drvdata(file);
0664 unsigned int n;
0665
0666 n = i->index;
0667 if (n >= TW68_INPUT_MAX)
0668 return -EINVAL;
0669 i->index = n;
0670 i->type = V4L2_INPUT_TYPE_CAMERA;
0671 snprintf(i->name, sizeof(i->name), "Composite %d", n);
0672
0673
0674 if (n == dev->input) {
0675 int v1 = tw_readb(TW68_STATUS1);
0676 int v2 = tw_readb(TW68_MVSN);
0677
0678 if (0 != (v1 & (1 << 7)))
0679 i->status |= V4L2_IN_ST_NO_SYNC;
0680 if (0 != (v1 & (1 << 6)))
0681 i->status |= V4L2_IN_ST_NO_H_LOCK;
0682 if (0 != (v1 & (1 << 2)))
0683 i->status |= V4L2_IN_ST_NO_SIGNAL;
0684 if (0 != (v1 & 1 << 1))
0685 i->status |= V4L2_IN_ST_NO_COLOR;
0686 if (0 != (v2 & (1 << 2)))
0687 i->status |= V4L2_IN_ST_MACROVISION;
0688 }
0689 i->std = video_devdata(file)->tvnorms;
0690 return 0;
0691 }
0692
0693 static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
0694 {
0695 struct tw68_dev *dev = video_drvdata(file);
0696
0697 *i = dev->input;
0698 return 0;
0699 }
0700
0701 static int tw68_s_input(struct file *file, void *priv, unsigned int i)
0702 {
0703 struct tw68_dev *dev = video_drvdata(file);
0704
0705 if (i >= TW68_INPUT_MAX)
0706 return -EINVAL;
0707 dev->input = i;
0708 tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);
0709 return 0;
0710 }
0711
0712 static int tw68_querycap(struct file *file, void *priv,
0713 struct v4l2_capability *cap)
0714 {
0715 strscpy(cap->driver, "tw68", sizeof(cap->driver));
0716 strscpy(cap->card, "Techwell Capture Card",
0717 sizeof(cap->card));
0718 return 0;
0719 }
0720
0721 static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
0722 {
0723 struct tw68_dev *dev = video_drvdata(file);
0724 unsigned int i;
0725
0726 if (vb2_is_busy(&dev->vidq))
0727 return -EBUSY;
0728
0729
0730 for (i = 0; i < TVNORMS; i++) {
0731 if (id == tvnorms[i].id)
0732 break;
0733 }
0734
0735
0736 if (i == TVNORMS) {
0737 for (i = 0; i < TVNORMS; i++)
0738 if (id & tvnorms[i].id)
0739 break;
0740 }
0741
0742 if (i == TVNORMS)
0743 return -EINVAL;
0744
0745 set_tvnorm(dev, &tvnorms[i]);
0746 return 0;
0747 }
0748
0749 static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
0750 {
0751 struct tw68_dev *dev = video_drvdata(file);
0752
0753 *id = dev->tvnorm->id;
0754 return 0;
0755 }
0756
0757 static int tw68_enum_fmt_vid_cap(struct file *file, void *priv,
0758 struct v4l2_fmtdesc *f)
0759 {
0760 if (f->index >= FORMATS)
0761 return -EINVAL;
0762
0763 f->pixelformat = formats[f->index].fourcc;
0764
0765 return 0;
0766 }
0767
0768
0769
0770
0771
0772 static void tw68_dump_regs(struct tw68_dev *dev)
0773 {
0774 unsigned char line[80];
0775 int i, j, k;
0776 unsigned char *cptr;
0777
0778 pr_info("Full dump of TW68 registers:\n");
0779
0780 for (i = 0; i < 0x100; i += 32) {
0781 cptr = line;
0782 cptr += sprintf(cptr, "%03x ", i);
0783
0784 for (j = i; j < i + 16; j += 4)
0785 cptr += sprintf(cptr, "%08x ", tw_readl(j));
0786 *cptr++ = ' ';
0787 for (; j < i + 32; j += 4)
0788 cptr += sprintf(cptr, "%08x ", tw_readl(j));
0789 *cptr++ = '\n';
0790 *cptr = 0;
0791 pr_info("%s", line);
0792 }
0793
0794 while (i < 0x400) {
0795 cptr = line;
0796 cptr += sprintf(cptr, "%03x ", i);
0797
0798 for (j = 0; j < 4; j++) {
0799 for (k = 0; k < 4; k++) {
0800 cptr += sprintf(cptr, "%02x ",
0801 tw_readb(i));
0802 i += 4;
0803 }
0804 *cptr++ = ' ';
0805 }
0806 *cptr++ = '\n';
0807 *cptr = 0;
0808 pr_info("%s", line);
0809 }
0810 }
0811
0812 static int vidioc_log_status(struct file *file, void *priv)
0813 {
0814 struct tw68_dev *dev = video_drvdata(file);
0815
0816 tw68_dump_regs(dev);
0817 return v4l2_ctrl_log_status(file, priv);
0818 }
0819
0820 #ifdef CONFIG_VIDEO_ADV_DEBUG
0821 static int vidioc_g_register(struct file *file, void *priv,
0822 struct v4l2_dbg_register *reg)
0823 {
0824 struct tw68_dev *dev = video_drvdata(file);
0825
0826 if (reg->size == 1)
0827 reg->val = tw_readb(reg->reg);
0828 else
0829 reg->val = tw_readl(reg->reg);
0830 return 0;
0831 }
0832
0833 static int vidioc_s_register(struct file *file, void *priv,
0834 const struct v4l2_dbg_register *reg)
0835 {
0836 struct tw68_dev *dev = video_drvdata(file);
0837
0838 if (reg->size == 1)
0839 tw_writeb(reg->reg, reg->val);
0840 else
0841 tw_writel(reg->reg & 0xffff, reg->val);
0842 return 0;
0843 }
0844 #endif
0845
0846 static const struct v4l2_ctrl_ops tw68_ctrl_ops = {
0847 .s_ctrl = tw68_s_ctrl,
0848 };
0849
0850 static const struct v4l2_file_operations video_fops = {
0851 .owner = THIS_MODULE,
0852 .open = v4l2_fh_open,
0853 .release = vb2_fop_release,
0854 .read = vb2_fop_read,
0855 .poll = vb2_fop_poll,
0856 .mmap = vb2_fop_mmap,
0857 .unlocked_ioctl = video_ioctl2,
0858 };
0859
0860 static const struct v4l2_ioctl_ops video_ioctl_ops = {
0861 .vidioc_querycap = tw68_querycap,
0862 .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap,
0863 .vidioc_reqbufs = vb2_ioctl_reqbufs,
0864 .vidioc_create_bufs = vb2_ioctl_create_bufs,
0865 .vidioc_querybuf = vb2_ioctl_querybuf,
0866 .vidioc_qbuf = vb2_ioctl_qbuf,
0867 .vidioc_dqbuf = vb2_ioctl_dqbuf,
0868 .vidioc_s_std = tw68_s_std,
0869 .vidioc_g_std = tw68_g_std,
0870 .vidioc_enum_input = tw68_enum_input,
0871 .vidioc_g_input = tw68_g_input,
0872 .vidioc_s_input = tw68_s_input,
0873 .vidioc_streamon = vb2_ioctl_streamon,
0874 .vidioc_streamoff = vb2_ioctl_streamoff,
0875 .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap,
0876 .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap,
0877 .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap,
0878 .vidioc_log_status = vidioc_log_status,
0879 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
0880 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
0881 #ifdef CONFIG_VIDEO_ADV_DEBUG
0882 .vidioc_g_register = vidioc_g_register,
0883 .vidioc_s_register = vidioc_s_register,
0884 #endif
0885 };
0886
0887 static const struct video_device tw68_video_template = {
0888 .name = "tw68_video",
0889 .fops = &video_fops,
0890 .ioctl_ops = &video_ioctl_ops,
0891 .release = video_device_release_empty,
0892 .tvnorms = TW68_NORMS,
0893 .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
0894 V4L2_CAP_STREAMING,
0895 };
0896
0897
0898
0899 void tw68_set_tvnorm_hw(struct tw68_dev *dev)
0900 {
0901 tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);
0902 }
0903
0904 int tw68_video_init1(struct tw68_dev *dev)
0905 {
0906 struct v4l2_ctrl_handler *hdl = &dev->hdl;
0907
0908 v4l2_ctrl_handler_init(hdl, 6);
0909 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
0910 V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);
0911 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
0912 V4L2_CID_CONTRAST, 0, 255, 1, 100);
0913 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
0914 V4L2_CID_SATURATION, 0, 255, 1, 128);
0915
0916 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
0917 V4L2_CID_HUE, -128, 127, 1, 0);
0918 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
0919 V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
0920 v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
0921 V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
0922 if (hdl->error) {
0923 v4l2_ctrl_handler_free(hdl);
0924 return hdl->error;
0925 }
0926 dev->v4l2_dev.ctrl_handler = hdl;
0927 v4l2_ctrl_handler_setup(hdl);
0928 return 0;
0929 }
0930
0931 int tw68_video_init2(struct tw68_dev *dev, int video_nr)
0932 {
0933 int ret;
0934
0935 set_tvnorm(dev, &tvnorms[0]);
0936
0937 dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
0938 dev->width = 720;
0939 dev->height = 576;
0940 dev->field = V4L2_FIELD_INTERLACED;
0941
0942 INIT_LIST_HEAD(&dev->active);
0943 dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0944 dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
0945 dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
0946 dev->vidq.ops = &tw68_video_qops;
0947 dev->vidq.mem_ops = &vb2_dma_sg_memops;
0948 dev->vidq.drv_priv = dev;
0949 dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
0950 dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
0951 dev->vidq.lock = &dev->lock;
0952 dev->vidq.min_buffers_needed = 2;
0953 dev->vidq.dev = &dev->pci->dev;
0954 ret = vb2_queue_init(&dev->vidq);
0955 if (ret)
0956 return ret;
0957 dev->vdev = tw68_video_template;
0958 dev->vdev.v4l2_dev = &dev->v4l2_dev;
0959 dev->vdev.lock = &dev->lock;
0960 dev->vdev.queue = &dev->vidq;
0961 video_set_drvdata(&dev->vdev, dev);
0962 return video_register_device(&dev->vdev, VFL_TYPE_VIDEO, video_nr);
0963 }
0964
0965
0966
0967
0968 void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
0969 {
0970 __u32 reg;
0971
0972
0973 tw_writel(TW68_INTSTAT, status);
0974
0975
0976
0977
0978
0979
0980 if (status & TW68_DMAPI) {
0981 struct tw68_buf *buf;
0982
0983 spin_lock(&dev->slock);
0984 buf = list_entry(dev->active.next, struct tw68_buf, list);
0985 list_del(&buf->list);
0986 spin_unlock(&dev->slock);
0987 buf->vb.vb2_buf.timestamp = ktime_get_ns();
0988 buf->vb.field = dev->field;
0989 buf->vb.sequence = dev->seqnr++;
0990 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
0991 status &= ~(TW68_DMAPI);
0992 if (0 == status)
0993 return;
0994 }
0995 if (status & (TW68_VLOCK | TW68_HLOCK))
0996 dev_dbg(&dev->pci->dev, "Lost sync\n");
0997 if (status & TW68_PABORT)
0998 dev_err(&dev->pci->dev, "PABORT interrupt\n");
0999 if (status & TW68_DMAPERR)
1000 dev_err(&dev->pci->dev, "DMAPERR interrupt\n");
1001
1002
1003
1004
1005 if (status & TW68_FDMIS)
1006 dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");
1007 if (status & TW68_FFOF) {
1008
1009 reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;
1010 tw_clearl(TW68_DMAC, TW68_FIFO_EN);
1011 dev_dbg(&dev->pci->dev, "FFOF interrupt\n");
1012 tw_setl(TW68_DMAC, reg);
1013 }
1014 if (status & TW68_FFERR)
1015 dev_dbg(&dev->pci->dev, "FFERR interrupt\n");
1016 }