diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-08-11 17:47:18 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-12 11:19:17 -0400 |
commit | 6b5a9492ca0c991bab1ac495624e17520e9edf18 (patch) | |
tree | 4ee2bc89d42ceae84989df965ce426932d3a6fbe /drivers | |
parent | a138ebcf826b9cbf6683e1db25905d7cd89e2dd1 (diff) |
V4L/DVB (12543): v4l: introduce string control support.
The upcoming RDS encoder needs support for string controls. This patch
implements the core implementation.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/v4l2-common.c | 2 | ||||
-rw-r--r-- | drivers/media/video/v4l2-compat-ioctl32.c | 65 | ||||
-rw-r--r-- | drivers/media/video/v4l2-ioctl.c | 10 |
3 files changed, 53 insertions, 24 deletions
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index b91d66a767d7..536150c34067 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -156,6 +156,8 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl, | |||
156 | return -EINVAL; | 156 | return -EINVAL; |
157 | if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED) | 157 | if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED) |
158 | return -EBUSY; | 158 | return -EBUSY; |
159 | if (qctrl->type == V4L2_CTRL_TYPE_STRING) | ||
160 | return 0; | ||
159 | if (qctrl->type == V4L2_CTRL_TYPE_BUTTON || | 161 | if (qctrl->type == V4L2_CTRL_TYPE_BUTTON || |
160 | qctrl->type == V4L2_CTRL_TYPE_INTEGER64 || | 162 | qctrl->type == V4L2_CTRL_TYPE_INTEGER64 || |
161 | qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) | 163 | qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) |
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 0056b115b42e..f788c41a3a5c 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c | |||
@@ -600,9 +600,35 @@ struct v4l2_ext_controls32 { | |||
600 | compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ | 600 | compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ |
601 | }; | 601 | }; |
602 | 602 | ||
603 | struct v4l2_ext_control32 { | ||
604 | __u32 id; | ||
605 | __u32 size; | ||
606 | __u32 reserved2[1]; | ||
607 | union { | ||
608 | __s32 value; | ||
609 | __s64 value64; | ||
610 | compat_caddr_t string; /* actually char * */ | ||
611 | }; | ||
612 | } __attribute__ ((packed)); | ||
613 | |||
614 | /* The following function really belong in v4l2-common, but that causes | ||
615 | a circular dependency between modules. We need to think about this, but | ||
616 | for now this will do. */ | ||
617 | |||
618 | /* Return non-zero if this control is a pointer type. Currently only | ||
619 | * type STRING is a pointer type. | ||
620 | * | ||
621 | * Note that there are currently no controls of this type, but at least the | ||
622 | * compat32 code is in place to properly handle such controls. Please | ||
623 | * remove this note once the first pointer controls are added. */ | ||
624 | static inline int ctrl_is_pointer(u32 id) | ||
625 | { | ||
626 | return 0; | ||
627 | } | ||
628 | |||
603 | static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) | 629 | static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) |
604 | { | 630 | { |
605 | struct v4l2_ext_control __user *ucontrols; | 631 | struct v4l2_ext_control32 __user *ucontrols; |
606 | struct v4l2_ext_control __user *kcontrols; | 632 | struct v4l2_ext_control __user *kcontrols; |
607 | int n; | 633 | int n; |
608 | compat_caddr_t p; | 634 | compat_caddr_t p; |
@@ -626,15 +652,17 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
626 | kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); | 652 | kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); |
627 | kp->controls = kcontrols; | 653 | kp->controls = kcontrols; |
628 | while (--n >= 0) { | 654 | while (--n >= 0) { |
629 | if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32))) | 655 | if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols))) |
630 | return -EFAULT; | ||
631 | if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2))) | ||
632 | return -EFAULT; | ||
633 | /* Note: if the void * part of the union ever becomes relevant | ||
634 | then we need to know the type of the control in order to do | ||
635 | the right thing here. Luckily, that is not yet an issue. */ | ||
636 | if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value))) | ||
637 | return -EFAULT; | 656 | return -EFAULT; |
657 | if (ctrl_is_pointer(kcontrols->id)) { | ||
658 | void __user *s; | ||
659 | |||
660 | if (get_user(p, &ucontrols->string)) | ||
661 | return -EFAULT; | ||
662 | s = compat_ptr(p); | ||
663 | if (put_user(s, &kcontrols->string)) | ||
664 | return -EFAULT; | ||
665 | } | ||
638 | ucontrols++; | 666 | ucontrols++; |
639 | kcontrols++; | 667 | kcontrols++; |
640 | } | 668 | } |
@@ -643,7 +671,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
643 | 671 | ||
644 | static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) | 672 | static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) |
645 | { | 673 | { |
646 | struct v4l2_ext_control __user *ucontrols; | 674 | struct v4l2_ext_control32 __user *ucontrols; |
647 | struct v4l2_ext_control __user *kcontrols = kp->controls; | 675 | struct v4l2_ext_control __user *kcontrols = kp->controls; |
648 | int n = kp->count; | 676 | int n = kp->count; |
649 | compat_caddr_t p; | 677 | compat_caddr_t p; |
@@ -664,15 +692,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
664 | return -EFAULT; | 692 | return -EFAULT; |
665 | 693 | ||
666 | while (--n >= 0) { | 694 | while (--n >= 0) { |
667 | if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32))) | 695 | unsigned size = sizeof(*ucontrols); |
668 | return -EFAULT; | 696 | |
669 | if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2, | 697 | /* Do not modify the pointer when copying a pointer control. |
670 | sizeof(ucontrols->reserved2))) | 698 | The contents of the pointer was changed, not the pointer |
671 | return -EFAULT; | 699 | itself. */ |
672 | /* Note: if the void * part of the union ever becomes relevant | 700 | if (ctrl_is_pointer(kcontrols->id)) |
673 | then we need to know the type of the control in order to do | 701 | size -= sizeof(ucontrols->value64); |
674 | the right thing here. Luckily, that is not yet an issue. */ | 702 | if (copy_in_user(ucontrols, kcontrols, size)) |
675 | if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value))) | ||
676 | return -EFAULT; | 703 | return -EFAULT; |
677 | ucontrols++; | 704 | ucontrols++; |
678 | kcontrols++; | 705 | kcontrols++; |
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index c32e67608ad4..30cc3347ae52 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c | |||
@@ -513,11 +513,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd, | |||
513 | dbgarg(cmd, ""); | 513 | dbgarg(cmd, ""); |
514 | printk(KERN_CONT "class=0x%x", c->ctrl_class); | 514 | printk(KERN_CONT "class=0x%x", c->ctrl_class); |
515 | for (i = 0; i < c->count; i++) { | 515 | for (i = 0; i < c->count; i++) { |
516 | if (show_vals) | 516 | if (show_vals && !c->controls[i].size) |
517 | printk(KERN_CONT " id/val=0x%x/0x%x", | 517 | printk(KERN_CONT " id/val=0x%x/0x%x", |
518 | c->controls[i].id, c->controls[i].value); | 518 | c->controls[i].id, c->controls[i].value); |
519 | else | 519 | else |
520 | printk(KERN_CONT " id=0x%x", c->controls[i].id); | 520 | printk(KERN_CONT " id=0x%x,size=%u", |
521 | c->controls[i].id, c->controls[i].size); | ||
521 | } | 522 | } |
522 | printk(KERN_CONT "\n"); | 523 | printk(KERN_CONT "\n"); |
523 | }; | 524 | }; |
@@ -528,10 +529,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) | |||
528 | 529 | ||
529 | /* zero the reserved fields */ | 530 | /* zero the reserved fields */ |
530 | c->reserved[0] = c->reserved[1] = 0; | 531 | c->reserved[0] = c->reserved[1] = 0; |
531 | for (i = 0; i < c->count; i++) { | 532 | for (i = 0; i < c->count; i++) |
532 | c->controls[i].reserved2[0] = 0; | 533 | c->controls[i].reserved2[0] = 0; |
533 | c->controls[i].reserved2[1] = 0; | 534 | |
534 | } | ||
535 | /* V4L2_CID_PRIVATE_BASE cannot be used as control class | 535 | /* V4L2_CID_PRIVATE_BASE cannot be used as control class |
536 | when using extended controls. | 536 | when using extended controls. |
537 | Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL | 537 | Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL |