|
@@ -32,6 +32,7 @@
|
|
|
|
|
|
#include "em28xx.h"
|
|
|
#include <media/tuner.h>
|
|
|
+#include <media/v4l2-common.h>
|
|
|
|
|
|
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
|
|
|
"Markus Rechberger <mrechberger@gmail.com>, " \
|
|
@@ -106,7 +107,31 @@ static const unsigned char saa7114_i2c_init[] = {
|
|
|
#define TVNORMS ARRAY_SIZE(tvnorms)
|
|
|
|
|
|
/* supported controls */
|
|
|
+/* Common to all boards */
|
|
|
static struct v4l2_queryctrl em28xx_qctrl[] = {
|
|
|
+ {
|
|
|
+ .id = V4L2_CID_AUDIO_VOLUME,
|
|
|
+ .type = V4L2_CTRL_TYPE_INTEGER,
|
|
|
+ .name = "Volume",
|
|
|
+ .minimum = 0x0,
|
|
|
+ .maximum = 0x1f,
|
|
|
+ .step = 0x1,
|
|
|
+ .default_value = 0x1f,
|
|
|
+ .flags = 0,
|
|
|
+ },{
|
|
|
+ .id = V4L2_CID_AUDIO_MUTE,
|
|
|
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
|
|
|
+ .name = "Mute",
|
|
|
+ .minimum = 0,
|
|
|
+ .maximum = 1,
|
|
|
+ .step = 1,
|
|
|
+ .default_value = 1,
|
|
|
+ .flags = 0,
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/* FIXME: These are specific to saa711x - should be moved to its code */
|
|
|
+static struct v4l2_queryctrl saa711x_qctrl[] = {
|
|
|
{
|
|
|
.id = V4L2_CID_BRIGHTNESS,
|
|
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
@@ -134,24 +159,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
|
|
|
.step = 0x1,
|
|
|
.default_value = 0x10,
|
|
|
.flags = 0,
|
|
|
- },{
|
|
|
- .id = V4L2_CID_AUDIO_VOLUME,
|
|
|
- .type = V4L2_CTRL_TYPE_INTEGER,
|
|
|
- .name = "Volume",
|
|
|
- .minimum = 0x0,
|
|
|
- .maximum = 0x1f,
|
|
|
- .step = 0x1,
|
|
|
- .default_value = 0x1f,
|
|
|
- .flags = 0,
|
|
|
- },{
|
|
|
- .id = V4L2_CID_AUDIO_MUTE,
|
|
|
- .type = V4L2_CTRL_TYPE_BOOLEAN,
|
|
|
- .name = "Mute",
|
|
|
- .minimum = 0,
|
|
|
- .maximum = 1,
|
|
|
- .step = 1,
|
|
|
- .default_value = 1,
|
|
|
- .flags = 0,
|
|
|
},{
|
|
|
.id = V4L2_CID_RED_BALANCE,
|
|
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
@@ -179,7 +186,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
|
|
|
.step = 0x1,
|
|
|
.default_value = 0x20,
|
|
|
.flags = 0,
|
|
|
- }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
static struct usb_driver em28xx_usb_driver;
|
|
@@ -674,7 +681,6 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
|
|
|
*/
|
|
|
static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
|
|
|
{
|
|
|
- s32 tmp;
|
|
|
switch (ctrl->id) {
|
|
|
case V4L2_CID_AUDIO_MUTE:
|
|
|
ctrl->value = dev->mute;
|
|
@@ -682,6 +688,16 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
|
|
|
case V4L2_CID_AUDIO_VOLUME:
|
|
|
ctrl->value = dev->volume;
|
|
|
return 0;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*FIXME: should be moved to saa711x */
|
|
|
+static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
|
|
|
+{
|
|
|
+ s32 tmp;
|
|
|
+ switch (ctrl->id) {
|
|
|
case V4L2_CID_BRIGHTNESS:
|
|
|
if ((tmp = em28xx_brightness_get(dev)) < 0)
|
|
|
return -EIO;
|
|
@@ -731,6 +747,15 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
|
|
|
case V4L2_CID_AUDIO_VOLUME:
|
|
|
dev->volume = ctrl->value;
|
|
|
return em28xx_audio_analog_set(dev);
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*FIXME: should be moved to saa711x */
|
|
|
+static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
|
|
|
+{
|
|
|
+ switch (ctrl->id) {
|
|
|
case V4L2_CID_BRIGHTNESS:
|
|
|
return em28xx_brightness_set(dev, ctrl->value);
|
|
|
case V4L2_CID_CONTRAST:
|
|
@@ -994,14 +1019,34 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
|
|
|
case VIDIOC_QUERYCTRL:
|
|
|
{
|
|
|
struct v4l2_queryctrl *qc = arg;
|
|
|
- u8 i, n;
|
|
|
- n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
|
|
|
- for (i = 0; i < n; i++)
|
|
|
- if (qc->id && qc->id == em28xx_qctrl[i].id) {
|
|
|
- memcpy(qc, &(em28xx_qctrl[i]),
|
|
|
+ int i, id=qc->id;
|
|
|
+
|
|
|
+ memset(qc,0,sizeof(*qc));
|
|
|
+ qc->id=id;
|
|
|
+
|
|
|
+ if (!dev->has_msp34xx) {
|
|
|
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
|
|
|
+ if (qc->id && qc->id == em28xx_qctrl[i].id) {
|
|
|
+ memcpy(qc, &(em28xx_qctrl[i]),
|
|
|
+ sizeof(*qc));
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (dev->decoder == EM28XX_TVP5150) {
|
|
|
+ em28xx_i2c_call_clients(dev,cmd,qc);
|
|
|
+ if (qc->type)
|
|
|
+ return 0;
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
|
|
|
+ if (qc->id && qc->id == saa711x_qctrl[i].id) {
|
|
|
+ memcpy(qc, &(saa711x_qctrl[i]),
|
|
|
sizeof(*qc));
|
|
|
return 0;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -1009,29 +1054,66 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
|
|
|
case VIDIOC_G_CTRL:
|
|
|
{
|
|
|
struct v4l2_control *ctrl = arg;
|
|
|
+ int retval=-EINVAL;
|
|
|
|
|
|
+ if (!dev->has_msp34xx)
|
|
|
+ retval=em28xx_get_ctrl(dev, ctrl);
|
|
|
+ if (retval==-EINVAL) {
|
|
|
+ if (dev->decoder == EM28XX_TVP5150) {
|
|
|
+ em28xx_i2c_call_clients(dev,cmd,arg);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- return em28xx_get_ctrl(dev, ctrl);
|
|
|
+ return saa711x_get_ctrl(dev, ctrl);
|
|
|
+ } else return retval;
|
|
|
}
|
|
|
|
|
|
- case VIDIOC_S_CTRL_OLD: /* ??? */
|
|
|
case VIDIOC_S_CTRL:
|
|
|
{
|
|
|
struct v4l2_control *ctrl = arg;
|
|
|
- u8 i, n;
|
|
|
-
|
|
|
+ u8 i;
|
|
|
+
|
|
|
+ if (!dev->has_msp34xx){
|
|
|
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
|
|
|
+ if (ctrl->id == em28xx_qctrl[i].id) {
|
|
|
+ if (ctrl->value <
|
|
|
+ em28xx_qctrl[i].minimum
|
|
|
+ || ctrl->value >
|
|
|
+ em28xx_qctrl[i].maximum)
|
|
|
+ return -ERANGE;
|
|
|
+ return em28xx_set_ctrl(dev, ctrl);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
|
|
|
- for (i = 0; i < n; i++)
|
|
|
- if (ctrl->id == em28xx_qctrl[i].id) {
|
|
|
- if (ctrl->value <
|
|
|
- em28xx_qctrl[i].minimum
|
|
|
- || ctrl->value >
|
|
|
- em28xx_qctrl[i].maximum)
|
|
|
- return -ERANGE;
|
|
|
+ if (dev->decoder == EM28XX_TVP5150) {
|
|
|
+ em28xx_i2c_call_clients(dev,cmd,arg);
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
|
|
|
- return em28xx_set_ctrl(dev, ctrl);
|
|
|
+ if (!dev->has_msp34xx){
|
|
|
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
|
|
|
+ if (ctrl->id == em28xx_qctrl[i].id) {
|
|
|
+ if (ctrl->value <
|
|
|
+ em28xx_qctrl[i].minimum
|
|
|
+ || ctrl->value >
|
|
|
+ em28xx_qctrl[i].maximum)
|
|
|
+ return -ERANGE;
|
|
|
+ return em28xx_set_ctrl(dev, ctrl);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
|
|
|
+ if (ctrl->id == saa711x_qctrl[i].id) {
|
|
|
+ if (ctrl->value <
|
|
|
+ saa711x_qctrl[i].minimum
|
|
|
+ || ctrl->value >
|
|
|
+ saa711x_qctrl[i].maximum)
|
|
|
+ return -ERANGE;
|
|
|
+ return saa711x_set_ctrl(dev, ctrl);
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -1850,9 +1932,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
|
|
|
struct em28xx *dev = usb_get_intfdata(interface);
|
|
|
usb_set_intfdata(interface, NULL);
|
|
|
|
|
|
+/*FIXME: IR should be disconnected */
|
|
|
+
|
|
|
if (!dev)
|
|
|
return;
|
|
|
|
|
|
+
|
|
|
down_write(&em28xx_disconnect);
|
|
|
|
|
|
down(&dev->lock);
|