Skip to content

Commit 5b0fa4f

Browse files
Oliver EndrissMauro Carvalho Chehab
authored andcommitted
V4L/DVB (3325): WSS output interface for av7110
- Implemented v4l2 api for sliced vbi data output to pass WSS data from userspace to the av7110 Signed-off-by: Oliver Endriss <[email protected]> Signed-off-by: Hans Verkuil <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent d312a46 commit 5b0fa4f

File tree

5 files changed

+149
-12
lines changed

5 files changed

+149
-12
lines changed

drivers/media/common/saa7146_fops.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
253253

254254
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
255255
DEB_S(("initializing vbi...\n"));
256-
result = saa7146_vbi_uops.open(dev,file);
256+
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
257+
result = saa7146_vbi_uops.open(dev,file);
258+
if (dev->ext_vv_data->vbi_fops.open)
259+
dev->ext_vv_data->vbi_fops.open(inode, file);
257260
} else {
258261
DEB_S(("initializing video...\n"));
259262
result = saa7146_video_uops.open(dev,file);
@@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file)
289292
return -ERESTARTSYS;
290293

291294
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
292-
saa7146_vbi_uops.release(dev,file);
295+
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
296+
saa7146_vbi_uops.release(dev,file);
297+
if (dev->ext_vv_data->vbi_fops.release)
298+
dev->ext_vv_data->vbi_fops.release(inode, file);
293299
} else {
294300
saa7146_video_uops.release(dev,file);
295301
}
@@ -382,7 +388,10 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
382388
}
383389
case V4L2_BUF_TYPE_VBI_CAPTURE: {
384390
// DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
385-
return saa7146_vbi_uops.read(file,data,count,ppos);
391+
if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
392+
return saa7146_vbi_uops.read(file,data,count,ppos);
393+
else
394+
return -EINVAL;
386395
}
387396
break;
388397
default:
@@ -391,12 +400,31 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
391400
}
392401
}
393402

403+
static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
404+
{
405+
struct saa7146_fh *fh = file->private_data;
406+
407+
switch (fh->type) {
408+
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
409+
return -EINVAL;
410+
case V4L2_BUF_TYPE_VBI_CAPTURE:
411+
if (fh->dev->ext_vv_data->vbi_fops.write)
412+
return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
413+
else
414+
return -EINVAL;
415+
default:
416+
BUG();
417+
return -EINVAL;
418+
}
419+
}
420+
394421
static struct file_operations video_fops =
395422
{
396423
.owner = THIS_MODULE,
397424
.open = fops_open,
398425
.release = fops_release,
399426
.read = fops_read,
427+
.write = fops_write,
400428
.poll = fops_poll,
401429
.mmap = fops_mmap,
402430
.ioctl = fops_ioctl,
@@ -468,7 +496,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
468496
memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
469497

470498
saa7146_video_uops.init(dev,vv);
471-
saa7146_vbi_uops.init(dev,vv);
499+
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
500+
saa7146_vbi_uops.init(dev,vv);
472501

473502
dev->vv_data = vv;
474503
dev->vv_callback = &vv_callback;

drivers/media/dvb/ttpci/av7110.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ struct av7110 {
229229
struct dvb_video_events video_events;
230230
video_size_t video_size;
231231

232+
u16 wssMode;
233+
u16 wssData;
234+
232235
u32 ir_config;
233236
u32 ir_command;
234237
void (*ir_handler)(struct av7110 *av7110, u32 ircom);

drivers/media/dvb/ttpci/av7110_hw.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ enum av7110_encoder_command {
167167
LoadVidCode,
168168
SetMonitorType,
169169
SetPanScanType,
170-
SetFreezeMode
170+
SetFreezeMode,
171+
SetWSSConfig
171172
};
172173

173174
enum av7110_rec_play_state {

drivers/media/dvb/ttpci/av7110_v4l.c

Lines changed: 109 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -490,13 +490,105 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
490490
dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
491491
break;
492492
}
493+
case VIDIOC_G_SLICED_VBI_CAP:
494+
{
495+
struct v4l2_sliced_vbi_cap *cap = arg;
496+
dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
497+
memset(cap, 0, sizeof *cap);
498+
if (FW_VERSION(av7110->arm_app) >= 0x2623) {
499+
cap->service_set = V4L2_SLICED_WSS_625;
500+
cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
501+
}
502+
break;
503+
}
504+
case VIDIOC_G_FMT:
505+
{
506+
struct v4l2_format *f = arg;
507+
dprintk(2, "VIDIOC_G_FMT:\n");
508+
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
509+
FW_VERSION(av7110->arm_app) < 0x2623)
510+
return -EAGAIN; /* handled by core driver */
511+
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
512+
if (av7110->wssMode) {
513+
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
514+
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
515+
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
516+
}
517+
break;
518+
}
519+
case VIDIOC_S_FMT:
520+
{
521+
struct v4l2_format *f = arg;
522+
dprintk(2, "VIDIOC_S_FMT\n");
523+
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
524+
FW_VERSION(av7110->arm_app) < 0x2623)
525+
return -EAGAIN; /* handled by core driver */
526+
if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
527+
f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
528+
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
529+
/* WSS controlled by firmware */
530+
av7110->wssMode = 0;
531+
av7110->wssData = 0;
532+
return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
533+
SetWSSConfig, 1, 0);
534+
} else {
535+
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
536+
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
537+
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
538+
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
539+
/* WSS controlled by userspace */
540+
av7110->wssMode = 1;
541+
av7110->wssData = 0;
542+
}
543+
break;
544+
}
493545
default:
494546
printk("no such ioctl\n");
495547
return -ENOIOCTLCMD;
496548
}
497549
return 0;
498550
}
499551

552+
static int av7110_vbi_reset(struct inode *inode, struct file *file)
553+
{
554+
struct saa7146_fh *fh = file->private_data;
555+
struct saa7146_dev *dev = fh->dev;
556+
struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
557+
558+
dprintk(2, "%s\n", __FUNCTION__);
559+
av7110->wssMode = 0;
560+
av7110->wssData = 0;
561+
if (FW_VERSION(av7110->arm_app) < 0x2623)
562+
return 0;
563+
else
564+
return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
565+
}
566+
567+
static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
568+
{
569+
struct saa7146_fh *fh = file->private_data;
570+
struct saa7146_dev *dev = fh->dev;
571+
struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
572+
struct v4l2_sliced_vbi_data d;
573+
int rc;
574+
575+
dprintk(2, "%s\n", __FUNCTION__);
576+
if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
577+
return -EINVAL;
578+
if (copy_from_user(&d, data, count))
579+
return -EFAULT;
580+
if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
581+
return -EINVAL;
582+
if (d.id) {
583+
av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
584+
rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
585+
2, 1, av7110->wssData);
586+
} else {
587+
av7110->wssData = 0;
588+
rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
589+
}
590+
return (rc < 0) ? rc : count;
591+
}
500592

501593
/****************************************************************************
502594
* INITIALIZATION
@@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = {
512604
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
513605
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
514606
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
607+
{ VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
608+
{ VIDIOC_G_FMT, SAA7146_BEFORE },
609+
{ VIDIOC_S_FMT, SAA7146_BEFORE },
515610
{ 0, 0 }
516611
};
517612

@@ -692,12 +787,11 @@ int av7110_init_v4l(struct av7110 *av7110)
692787
saa7146_vv_release(dev);
693788
return -ENODEV;
694789
}
695-
if (av7110->analog_tuner_flags) {
696-
if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
697-
ERR(("cannot register vbi v4l2 device. skipping.\n"));
698-
} else {
790+
if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
791+
ERR(("cannot register vbi v4l2 device. skipping.\n"));
792+
} else {
793+
if (av7110->analog_tuner_flags)
699794
av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
700-
}
701795
}
702796
return 0;
703797
}
@@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
778872
static struct saa7146_ext_vv av7110_vv_data_st = {
779873
.inputs = 1,
780874
.audios = 1,
781-
.capabilities = 0,
875+
.capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
782876
.flags = 0,
783877

784878
.stds = &standard[0],
@@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
787881

788882
.ioctls = &ioctls[0],
789883
.ioctl = av7110_ioctl,
884+
885+
.vbi_fops.open = av7110_vbi_reset,
886+
.vbi_fops.release = av7110_vbi_reset,
887+
.vbi_fops.write = av7110_vbi_write,
790888
};
791889

792890
static struct saa7146_ext_vv av7110_vv_data_c = {
793891
.inputs = 1,
794892
.audios = 1,
795-
.capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
893+
.capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
796894
.flags = SAA7146_USE_PORT_B_FOR_VBI,
797895

798896
.stds = &standard[0],
@@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
801899

802900
.ioctls = &ioctls[0],
803901
.ioctl = av7110_ioctl,
902+
903+
.vbi_fops.open = av7110_vbi_reset,
904+
.vbi_fops.release = av7110_vbi_reset,
905+
.vbi_fops.write = av7110_vbi_write,
804906
};
805907

include/media/saa7146_vv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ struct saa7146_ext_vv
178178

179179
struct saa7146_extension_ioctls *ioctls;
180180
int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
181+
182+
struct file_operations vbi_fops;
181183
};
182184

183185
struct saa7146_use_ops {

0 commit comments

Comments
 (0)