diff options
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-video.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 161 |
1 files changed, 102 insertions, 59 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index ab079d9256c4..a6bdbc21410e 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -124,7 +124,7 @@ static struct em28xx_fmt format[] = { | |||
124 | 124 | ||
125 | /* supported controls */ | 125 | /* supported controls */ |
126 | /* Common to all boards */ | 126 | /* Common to all boards */ |
127 | static struct v4l2_queryctrl em28xx_qctrl[] = { | 127 | static struct v4l2_queryctrl ac97_qctrl[] = { |
128 | { | 128 | { |
129 | .id = V4L2_CID_AUDIO_VOLUME, | 129 | .id = V4L2_CID_AUDIO_VOLUME, |
130 | .type = V4L2_CTRL_TYPE_INTEGER, | 130 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -133,7 +133,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { | |||
133 | .maximum = 0x1f, | 133 | .maximum = 0x1f, |
134 | .step = 0x1, | 134 | .step = 0x1, |
135 | .default_value = 0x1f, | 135 | .default_value = 0x1f, |
136 | .flags = 0, | 136 | .flags = V4L2_CTRL_FLAG_SLIDER, |
137 | }, { | 137 | }, { |
138 | .id = V4L2_CID_AUDIO_MUTE, | 138 | .id = V4L2_CID_AUDIO_MUTE, |
139 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 139 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
@@ -609,10 +609,29 @@ static void res_free(struct em28xx_fh *fh) | |||
609 | } | 609 | } |
610 | 610 | ||
611 | /* | 611 | /* |
612 | * em28xx_get_ctrl() | 612 | * ac97_queryctrl() |
613 | * return the current saturation, brightness or contrast, mute state | 613 | * return the ac97 supported controls |
614 | */ | 614 | */ |
615 | static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) | 615 | static int ac97_queryctrl(struct v4l2_queryctrl *qc) |
616 | { | ||
617 | int i; | ||
618 | |||
619 | for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) { | ||
620 | if (qc->id && qc->id == ac97_qctrl[i].id) { | ||
621 | memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc)); | ||
622 | return 0; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | /* Control is not ac97 related */ | ||
627 | return 1; | ||
628 | } | ||
629 | |||
630 | /* | ||
631 | * ac97_get_ctrl() | ||
632 | * return the current values for ac97 mute and volume | ||
633 | */ | ||
634 | static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) | ||
616 | { | 635 | { |
617 | switch (ctrl->id) { | 636 | switch (ctrl->id) { |
618 | case V4L2_CID_AUDIO_MUTE: | 637 | case V4L2_CID_AUDIO_MUTE: |
@@ -622,29 +641,41 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) | |||
622 | ctrl->value = dev->volume; | 641 | ctrl->value = dev->volume; |
623 | return 0; | 642 | return 0; |
624 | default: | 643 | default: |
625 | return -EINVAL; | 644 | /* Control is not ac97 related */ |
645 | return 1; | ||
626 | } | 646 | } |
627 | } | 647 | } |
628 | 648 | ||
629 | /* | 649 | /* |
630 | * em28xx_set_ctrl() | 650 | * ac97_set_ctrl() |
631 | * mute or set new saturation, brightness or contrast | 651 | * set values for ac97 mute and volume |
632 | */ | 652 | */ |
633 | static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) | 653 | static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) |
634 | { | 654 | { |
655 | int i; | ||
656 | |||
657 | for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) | ||
658 | if (ctrl->id == ac97_qctrl[i].id) | ||
659 | goto handle; | ||
660 | |||
661 | /* Announce that hasn't handle it */ | ||
662 | return 1; | ||
663 | |||
664 | handle: | ||
665 | if (ctrl->value < ac97_qctrl[i].minimum || | ||
666 | ctrl->value > ac97_qctrl[i].maximum) | ||
667 | return -ERANGE; | ||
668 | |||
635 | switch (ctrl->id) { | 669 | switch (ctrl->id) { |
636 | case V4L2_CID_AUDIO_MUTE: | 670 | case V4L2_CID_AUDIO_MUTE: |
637 | if (ctrl->value != dev->mute) { | 671 | dev->mute = ctrl->value; |
638 | dev->mute = ctrl->value; | 672 | break; |
639 | return em28xx_audio_analog_set(dev); | ||
640 | } | ||
641 | return 0; | ||
642 | case V4L2_CID_AUDIO_VOLUME: | 673 | case V4L2_CID_AUDIO_VOLUME: |
643 | dev->volume = ctrl->value; | 674 | dev->volume = ctrl->value; |
644 | return em28xx_audio_analog_set(dev); | 675 | break; |
645 | default: | ||
646 | return -EINVAL; | ||
647 | } | 676 | } |
677 | |||
678 | return em28xx_audio_analog_set(dev); | ||
648 | } | 679 | } |
649 | 680 | ||
650 | static int check_dev(struct em28xx *dev) | 681 | static int check_dev(struct em28xx *dev) |
@@ -974,6 +1005,9 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) | |||
974 | struct em28xx_fh *fh = priv; | 1005 | struct em28xx_fh *fh = priv; |
975 | struct em28xx *dev = fh->dev; | 1006 | struct em28xx *dev = fh->dev; |
976 | 1007 | ||
1008 | if (!dev->audio_mode.has_audio) | ||
1009 | return -EINVAL; | ||
1010 | |||
977 | switch (a->index) { | 1011 | switch (a->index) { |
978 | case EM28XX_AMUX_VIDEO: | 1012 | case EM28XX_AMUX_VIDEO: |
979 | strcpy(a->name, "Television"); | 1013 | strcpy(a->name, "Television"); |
@@ -1015,6 +1049,9 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) | |||
1015 | struct em28xx *dev = fh->dev; | 1049 | struct em28xx *dev = fh->dev; |
1016 | 1050 | ||
1017 | 1051 | ||
1052 | if (!dev->audio_mode.has_audio) | ||
1053 | return -EINVAL; | ||
1054 | |||
1018 | if (a->index >= MAX_EM28XX_INPUT) | 1055 | if (a->index >= MAX_EM28XX_INPUT) |
1019 | return -EINVAL; | 1056 | return -EINVAL; |
1020 | if (0 == INPUT(a->index)->type) | 1057 | if (0 == INPUT(a->index)->type) |
@@ -1038,7 +1075,6 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
1038 | struct em28xx_fh *fh = priv; | 1075 | struct em28xx_fh *fh = priv; |
1039 | struct em28xx *dev = fh->dev; | 1076 | struct em28xx *dev = fh->dev; |
1040 | int id = qc->id; | 1077 | int id = qc->id; |
1041 | int i; | ||
1042 | int rc; | 1078 | int rc; |
1043 | 1079 | ||
1044 | rc = check_dev(dev); | 1080 | rc = check_dev(dev); |
@@ -1049,15 +1085,14 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
1049 | 1085 | ||
1050 | qc->id = id; | 1086 | qc->id = id; |
1051 | 1087 | ||
1052 | if (!dev->board.has_msp34xx) { | 1088 | /* enumberate AC97 controls */ |
1053 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { | 1089 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { |
1054 | if (qc->id && qc->id == em28xx_qctrl[i].id) { | 1090 | rc = ac97_queryctrl(qc); |
1055 | memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); | 1091 | if (!rc) |
1056 | return 0; | 1092 | return 0; |
1057 | } | ||
1058 | } | ||
1059 | } | 1093 | } |
1060 | 1094 | ||
1095 | /* enumberate V4L2 device controls */ | ||
1061 | mutex_lock(&dev->lock); | 1096 | mutex_lock(&dev->lock); |
1062 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc); | 1097 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc); |
1063 | mutex_unlock(&dev->lock); | 1098 | mutex_unlock(&dev->lock); |
@@ -1082,14 +1117,16 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
1082 | 1117 | ||
1083 | mutex_lock(&dev->lock); | 1118 | mutex_lock(&dev->lock); |
1084 | 1119 | ||
1085 | if (dev->board.has_msp34xx) | 1120 | /* Set an AC97 control */ |
1121 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) | ||
1122 | rc = ac97_get_ctrl(dev, ctrl); | ||
1123 | else | ||
1124 | rc = 1; | ||
1125 | |||
1126 | /* It were not an AC97 control. Sends it to the v4l2 dev interface */ | ||
1127 | if (rc == 1) { | ||
1086 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); | 1128 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); |
1087 | else { | 1129 | rc = 0; |
1088 | rc = em28xx_get_ctrl(dev, ctrl); | ||
1089 | if (rc < 0) { | ||
1090 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); | ||
1091 | rc = 0; | ||
1092 | } | ||
1093 | } | 1130 | } |
1094 | 1131 | ||
1095 | mutex_unlock(&dev->lock); | 1132 | mutex_unlock(&dev->lock); |
@@ -1101,7 +1138,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
1101 | { | 1138 | { |
1102 | struct em28xx_fh *fh = priv; | 1139 | struct em28xx_fh *fh = priv; |
1103 | struct em28xx *dev = fh->dev; | 1140 | struct em28xx *dev = fh->dev; |
1104 | u8 i; | ||
1105 | int rc; | 1141 | int rc; |
1106 | 1142 | ||
1107 | rc = check_dev(dev); | 1143 | rc = check_dev(dev); |
@@ -1110,28 +1146,31 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
1110 | 1146 | ||
1111 | mutex_lock(&dev->lock); | 1147 | mutex_lock(&dev->lock); |
1112 | 1148 | ||
1113 | if (dev->board.has_msp34xx) | 1149 | /* Set an AC97 control */ |
1114 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); | 1150 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) |
1115 | else { | 1151 | rc = ac97_set_ctrl(dev, ctrl); |
1152 | else | ||
1116 | rc = 1; | 1153 | rc = 1; |
1117 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { | ||
1118 | if (ctrl->id == em28xx_qctrl[i].id) { | ||
1119 | if (ctrl->value < em28xx_qctrl[i].minimum || | ||
1120 | ctrl->value > em28xx_qctrl[i].maximum) { | ||
1121 | rc = -ERANGE; | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | rc = em28xx_set_ctrl(dev, ctrl); | ||
1126 | break; | ||
1127 | } | ||
1128 | } | ||
1129 | } | ||
1130 | 1154 | ||
1131 | /* Control not found - try to send it to the attached devices */ | 1155 | /* It isn't an AC97 control. Sends it to the v4l2 dev interface */ |
1132 | if (rc == 1) { | 1156 | if (rc == 1) { |
1133 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); | 1157 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); |
1134 | rc = 0; | 1158 | |
1159 | /* | ||
1160 | * In the case of non-AC97 volume controls, we still need | ||
1161 | * to do some setups at em28xx, in order to mute/unmute | ||
1162 | * and to adjust audio volume. However, the value ranges | ||
1163 | * should be checked by the corresponding V4L subdriver. | ||
1164 | */ | ||
1165 | switch (ctrl->id) { | ||
1166 | case V4L2_CID_AUDIO_MUTE: | ||
1167 | dev->mute = ctrl->value; | ||
1168 | rc = em28xx_audio_analog_set(dev); | ||
1169 | break; | ||
1170 | case V4L2_CID_AUDIO_VOLUME: | ||
1171 | dev->volume = ctrl->value; | ||
1172 | rc = em28xx_audio_analog_set(dev); | ||
1173 | } | ||
1135 | } | 1174 | } |
1136 | 1175 | ||
1137 | mutex_unlock(&dev->lock); | 1176 | mutex_unlock(&dev->lock); |
@@ -1275,8 +1314,9 @@ static int vidioc_g_register(struct file *file, void *priv, | |||
1275 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); | 1314 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); |
1276 | return 0; | 1315 | return 0; |
1277 | case V4L2_CHIP_MATCH_I2C_ADDR: | 1316 | case V4L2_CHIP_MATCH_I2C_ADDR: |
1278 | /* Not supported yet */ | 1317 | /* TODO: is this correct? */ |
1279 | return -EINVAL; | 1318 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); |
1319 | return 0; | ||
1280 | default: | 1320 | default: |
1281 | if (!v4l2_chip_match_host(®->match)) | 1321 | if (!v4l2_chip_match_host(®->match)) |
1282 | return -EINVAL; | 1322 | return -EINVAL; |
@@ -1327,8 +1367,9 @@ static int vidioc_s_register(struct file *file, void *priv, | |||
1327 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); | 1367 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); |
1328 | return 0; | 1368 | return 0; |
1329 | case V4L2_CHIP_MATCH_I2C_ADDR: | 1369 | case V4L2_CHIP_MATCH_I2C_ADDR: |
1330 | /* Not supported yet */ | 1370 | /* TODO: is this correct? */ |
1331 | return -EINVAL; | 1371 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); |
1372 | return 0; | ||
1332 | default: | 1373 | default: |
1333 | if (!v4l2_chip_match_host(®->match)) | 1374 | if (!v4l2_chip_match_host(®->match)) |
1334 | return -EINVAL; | 1375 | return -EINVAL; |
@@ -1431,9 +1472,11 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
1431 | cap->capabilities = | 1472 | cap->capabilities = |
1432 | V4L2_CAP_SLICED_VBI_CAPTURE | | 1473 | V4L2_CAP_SLICED_VBI_CAPTURE | |
1433 | V4L2_CAP_VIDEO_CAPTURE | | 1474 | V4L2_CAP_VIDEO_CAPTURE | |
1434 | V4L2_CAP_AUDIO | | ||
1435 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; | 1475 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; |
1436 | 1476 | ||
1477 | if (dev->audio_mode.has_audio) | ||
1478 | cap->capabilities |= V4L2_CAP_AUDIO; | ||
1479 | |||
1437 | if (dev->tuner_type != TUNER_ABSENT) | 1480 | if (dev->tuner_type != TUNER_ABSENT) |
1438 | cap->capabilities |= V4L2_CAP_TUNER; | 1481 | cap->capabilities |= V4L2_CAP_TUNER; |
1439 | 1482 | ||
@@ -1654,9 +1697,9 @@ static int radio_queryctrl(struct file *file, void *priv, | |||
1654 | qc->id >= V4L2_CID_LASTP1) | 1697 | qc->id >= V4L2_CID_LASTP1) |
1655 | return -EINVAL; | 1698 | return -EINVAL; |
1656 | 1699 | ||
1657 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { | 1700 | for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) { |
1658 | if (qc->id && qc->id == em28xx_qctrl[i].id) { | 1701 | if (qc->id && qc->id == ac97_qctrl[i].id) { |
1659 | memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); | 1702 | memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc)); |
1660 | return 0; | 1703 | return 0; |
1661 | } | 1704 | } |
1662 | } | 1705 | } |