aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/usb
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2013-04-30 09:01:04 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-04-30 09:01:04 -0300
commitdf90e2258950fd631cdbf322c1ee1f22068391aa (patch)
tree0b6dd2717c04bb7f93db6abdeda208aeea4cd74e /drivers/media/usb
parentaad797c89903d570c17f6affc770eb98afd74e62 (diff)
parent02615ed5e1b2283db2495af3cf8f4ee172c77d80 (diff)
downloadvexpress-lsk-df90e2258950fd631cdbf322c1ee1f22068391aa.tar.gz
Merge branch 'devel-for-v3.10' into v4l_for_linus
* patchwork: (831 commits) [media] cx88: make core less verbose [media] em28xx: fix oops at em28xx_dvb_bus_ctrl() [media] s5c73m3: fix indentation of the help section in Kconfig [media] cx25821-alsa: get rid of a __must_check warning [media] cx25821-video: declare cx25821_vidioc_s_std as static [media] cx25821-video: remove maxw from cx25821_vidioc_try_fmt_vid_cap [media] r820t: Remove a warning for an unused value [media] dib0090: Fix a warning at dib0090_set_EFUSE [media] dib8000: fix a warning [media] dib8000: Fix sub-channel range [media] dib8000: store dtv_property_cache in a temp var [media] dib8000: warning fix: declare internal functions as static [media] r820t: quiet gcc warning on n_ring [media] r820t: memory leak in release() [media] r820t: precendence bug in r820t_xtal_check() [media] videodev2.h: Remove the unused old V4L1 buffer types [media] anysee: Grammar s/report the/report to/ [media] anysee: Initialize ret = 0 in anysee_frontend_attach() [media] media: videobuf2: fix the length check for mmap [media] em28xx: save isoc endpoint number for DVB only if endpoint has alt settings with xMaxPacketSize != 0 ... Conflicts: drivers/media/pci/cx25821/cx25821-video.c drivers/media/platform/Kconfig
Diffstat (limited to 'drivers/media/usb')
-rw-r--r--drivers/media/usb/au0828/au0828-core.c61
-rw-r--r--drivers/media/usb/au0828/au0828-video.c299
-rw-r--r--drivers/media/usb/au0828/au0828.h7
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c1182
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c8
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c85
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c59
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c4
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c25
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c601
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h55
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig8
-rw-r--r--drivers/media/usb/dvb-usb-v2/Makefile5
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c79
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c600
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h49
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c48
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.h3
-rw-r--r--drivers/media/usb/dvb-usb-v2/az6007.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/cypress_firmware.c134
-rw-r--r--drivers/media/usb/dvb-usb-v2/cypress_firmware.h31
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h9
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c311
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c43
-rw-r--r--drivers/media/usb/dvb-usb-v2/it913x.c1
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h5
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c36
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h1
-rw-r--r--drivers/media/usb/dvb-usb-v2/usb_urb.c36
-rw-r--r--drivers/media/usb/dvb-usb/cinergyT2-fe.c3
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c465
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c5
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c19
-rw-r--r--drivers/media/usb/dvb-usb/m920x.c10
-rw-r--r--drivers/media/usb/em28xx/Kconfig1
-rw-r--r--drivers/media/usb/em28xx/Makefile2
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c434
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c366
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c45
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c125
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c691
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h35
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c415
-rw-r--r--drivers/media/usb/em28xx/em28xx.h231
-rw-r--r--drivers/media/usb/gspca/autogain_functions.h183
-rw-r--r--drivers/media/usb/gspca/benq.c2
-rw-r--r--drivers/media/usb/gspca/conex.c12
-rw-r--r--drivers/media/usb/gspca/cpia1.c33
-rw-r--r--drivers/media/usb/gspca/etoms.c12
-rw-r--r--drivers/media/usb/gspca/gl860/gl860.c224
-rw-r--r--drivers/media/usb/gspca/gspca.c240
-rw-r--r--drivers/media/usb/gspca/gspca.h70
-rw-r--r--drivers/media/usb/gspca/jeilinj.c2
-rw-r--r--drivers/media/usb/gspca/konica.c28
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_bridge.h27
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_core.c22
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.c404
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.c312
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.h3
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.c469
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.c471
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.c352
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.c291
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.h9
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_sensor.h3
-rw-r--r--drivers/media/usb/gspca/mr97310a.c8
-rw-r--r--drivers/media/usb/gspca/ov519.c81
-rw-r--r--drivers/media/usb/gspca/ov534.c2
-rw-r--r--drivers/media/usb/gspca/pac207.c2
-rw-r--r--drivers/media/usb/gspca/pac7302.c9
-rw-r--r--drivers/media/usb/gspca/pac7311.c5
-rw-r--r--drivers/media/usb/gspca/pac_common.h2
-rw-r--r--drivers/media/usb/gspca/sn9c2028.c4
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c2
-rw-r--r--drivers/media/usb/gspca/sonixb.c22
-rw-r--r--drivers/media/usb/gspca/sonixj.c556
-rw-r--r--drivers/media/usb/gspca/spca1528.c4
-rw-r--r--drivers/media/usb/gspca/spca500.c36
-rw-r--r--drivers/media/usb/gspca/spca501.c44
-rw-r--r--drivers/media/usb/gspca/spca505.c42
-rw-r--r--drivers/media/usb/gspca/spca508.c41
-rw-r--r--drivers/media/usb/gspca/spca561.c70
-rw-r--r--drivers/media/usb/gspca/sq905.c2
-rw-r--r--drivers/media/usb/gspca/sq905c.c6
-rw-r--r--drivers/media/usb/gspca/sq930x.c4
-rw-r--r--drivers/media/usb/gspca/stv0680.c14
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx.c17
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c8
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c14
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c2
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c10
-rw-r--r--drivers/media/usb/gspca/sunplus.c27
-rw-r--r--drivers/media/usb/gspca/vc032x.c9
-rw-r--r--drivers/media/usb/gspca/w996Xcf.c5
-rw-r--r--drivers/media/usb/gspca/zc3xx.c3
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c15
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c945
-rw-r--r--drivers/media/usb/hdpvr/hdpvr.h19
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.h2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c10
-rw-r--r--drivers/media/usb/pwc/pwc-if.c1
-rw-r--r--drivers/media/usb/s2255/s2255drv.c441
-rw-r--r--drivers/media/usb/siano/smsusb.c158
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c14
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c309
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.h8
-rw-r--r--drivers/media/usb/tlg2300/pd-common.h26
-rw-r--r--drivers/media/usb/tlg2300/pd-main.c16
-rw-r--r--drivers/media/usb/tlg2300/pd-radio.c229
-rw-r--r--drivers/media/usb/tlg2300/pd-video.c303
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c16
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c10
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c20
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c10
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c2
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c1
128 files changed, 6073 insertions, 7374 deletions
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 1e6f40ef1c6..bd9d19a73ef 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -125,6 +125,26 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
return status;
}
+static void au0828_usb_release(struct au0828_dev *dev)
+{
+ /* I2C */
+ au0828_i2c_unregister(dev);
+
+ kfree(dev);
+}
+
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
+{
+ struct au0828_dev *dev =
+ container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ au0828_usb_release(dev);
+}
+#endif
+
static void au0828_usb_disconnect(struct usb_interface *interface)
{
struct au0828_dev *dev = usb_get_intfdata(interface);
@@ -134,26 +154,19 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
/* Digital TV */
au0828_dvb_unregister(dev);
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
- au0828_analog_unregister(dev);
-#endif
-
- /* I2C */
- au0828_i2c_unregister(dev);
-
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- v4l2_device_unregister(&dev->v4l2_dev);
-#endif
-
usb_set_intfdata(interface, NULL);
-
mutex_lock(&dev->mutex);
dev->usbdev = NULL;
mutex_unlock(&dev->mutex);
-
- kfree(dev);
-
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+ au0828_analog_unregister(dev);
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ v4l2_device_put(&dev->v4l2_dev);
+ return;
+ }
+#endif
+ au0828_usb_release(dev);
}
static int au0828_usb_probe(struct usb_interface *interface,
@@ -202,15 +215,27 @@ static int au0828_usb_probe(struct usb_interface *interface,
dev->boardnr = id->driver_info;
#ifdef CONFIG_VIDEO_AU0828_V4L2
+ dev->v4l2_dev.release = au0828_usb_v4l2_release;
+
/* Create the v4l2_device */
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
- printk(KERN_ERR "%s() v4l2_device_register failed\n",
+ pr_err("%s() v4l2_device_register failed\n",
+ __func__);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return retval;
+ }
+ /* This control handler will inherit the controls from au8522 */
+ retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
+ if (retval) {
+ pr_err("%s() v4l2_ctrl_handler_init failed\n",
__func__);
mutex_unlock(&dev->lock);
kfree(dev);
- return -EIO;
+ return retval;
}
+ dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
#endif
/* Power Up the bridge */
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 8b9e8268e91..75ac9947cda 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -35,6 +35,7 @@
#include <linux/suspend.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-chip-ident.h>
#include <media/tuner.h>
#include "au0828.h"
@@ -58,6 +59,12 @@ do {\
} \
} while (0)
+static inline void i2c_gate_ctrl(struct au0828_dev *dev, int val)
+{
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, val);
+}
+
static inline void print_err_status(struct au0828_dev *dev,
int packet, int status)
{
@@ -988,20 +995,22 @@ static int au0828_v4l2_open(struct file *filp)
fh->type = type;
fh->dev = dev;
+ v4l2_fh_init(&fh->fh, vdev);
filp->private_data = fh;
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (mutex_lock_interruptible(&dev->lock)) {
+ kfree(fh);
+ return -ERESTARTSYS;
+ }
+ if (dev->users == 0) {
/* set au0828 interface0 to AS5 here again */
ret = usb_set_interface(dev->usbdev, 0, 5);
if (ret < 0) {
+ mutex_unlock(&dev->lock);
printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+ kfree(fh);
return -EBUSY;
}
- dev->width = NTSC_STD_W;
- dev->height = NTSC_STD_H;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->width * dev->height;
- dev->bytesperline = dev->width * 2;
au0828_analog_stream_enable(dev);
au0828_analog_stream_reset(dev);
@@ -1014,6 +1023,7 @@ static int au0828_v4l2_open(struct file *filp)
}
dev->users++;
+ mutex_unlock(&dev->lock);
videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
NULL, &dev->slock,
@@ -1023,14 +1033,13 @@ static int au0828_v4l2_open(struct file *filp)
&dev->lock);
/* VBI Setup */
- dev->vbi_width = 720;
- dev->vbi_height = 1;
videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
NULL, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct au0828_buffer), fh,
&dev->lock);
+ v4l2_fh_add(&fh->fh);
return ret;
}
@@ -1040,6 +1049,9 @@ static int au0828_v4l2_close(struct file *filp)
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
+ mutex_lock(&dev->lock);
if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
/* Cancel timeout thread in case they didn't call streamoff */
dev->vid_timeout_running = 0;
@@ -1058,19 +1070,14 @@ static int au0828_v4l2_close(struct file *filp)
res_free(fh, AU0828_RESOURCE_VBI);
}
- if (dev->users == 1) {
- if (dev->dev_state & DEV_DISCONNECTED) {
- au0828_analog_unregister(dev);
- kfree(dev);
- return 0;
- }
-
+ if (dev->users == 1 && video_is_registered(video_devdata(filp))) {
au0828_analog_stream_disable(dev);
au0828_uninit_isoc(dev);
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ dev->std_set_in_tuner_core = 0;
/* When close the device, set the usb intf0 into alt0 to free
USB bandwidth */
@@ -1078,6 +1085,7 @@ static int au0828_v4l2_close(struct file *filp)
if (ret < 0)
printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
}
+ mutex_unlock(&dev->lock);
videobuf_mmap_free(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vbiq);
@@ -1087,6 +1095,26 @@ static int au0828_v4l2_close(struct file *filp)
return 0;
}
+/* Must be called with dev->lock held */
+static void au0828_init_tuner(struct au0828_dev *dev)
+{
+ struct v4l2_frequency f = {
+ .frequency = dev->ctrl_freq,
+ .type = V4L2_TUNER_ANALOG_TV,
+ };
+
+ if (dev->std_set_in_tuner_core)
+ return;
+ dev->std_set_in_tuner_core = 1;
+ i2c_gate_ctrl(dev, 1);
+ /* If we've never sent the standard in tuner core, do so now.
+ We don't do this at device probe because we don't want to
+ incur the cost of a firmware load */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->std);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ i2c_gate_ctrl(dev, 0);
+}
+
static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
@@ -1098,6 +1126,11 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
if (rc < 0)
return rc;
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ au0828_init_tuner(dev);
+ mutex_unlock(&dev->lock);
+
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (res_locked(dev, AU0828_RESOURCE_VIDEO))
return -EBUSY;
@@ -1128,23 +1161,32 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
{
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
- int rc;
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned int res;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
+ if (check_dev(dev) < 0)
+ return POLLERR;
+
+ res = v4l2_ctrl_poll(filp, wait);
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return res;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ au0828_init_tuner(dev);
+ mutex_unlock(&dev->lock);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (!res_get(fh, AU0828_RESOURCE_VIDEO))
return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ return res | videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ }
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
if (!res_get(fh, AU0828_RESOURCE_VBI))
return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- } else {
- return POLLERR;
+ return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
}
+ return POLLERR;
}
static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -1172,9 +1214,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
int width = format->fmt.pix.width;
int height = format->fmt.pix.height;
- if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
/* If they are demanding a format other than the one we support,
bail out (tvtime asks for UYVY and then retries with YUYV) */
if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
@@ -1193,6 +1232,7 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
format->fmt.pix.sizeimage = width * height * 2;
format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ format->fmt.pix.priv = 0;
if (cmd == VIDIOC_TRY_FMT)
return 0;
@@ -1226,35 +1266,28 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct au0828_fh *fh = priv;
+ struct video_device *vdev = video_devdata(file);
+ struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
strlcpy(cap->driver, "au0828", sizeof(cap->driver));
strlcpy(cap->card, dev->board.name, sizeof(cap->card));
- strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+ usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info));
- /*set the device capabilities */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_AUDIO |
+ /* set the device capabilities */
+ cap->device_caps = V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_TUNER;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ else
+ cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE;
return 0;
}
@@ -1286,6 +1319,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = dev->frame_size;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1320,24 +1354,34 @@ out:
return rc;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+ dev->std = norm;
+
+ au0828_init_tuner(dev);
+
+ i2c_gate_ctrl(dev, 1);
/* FIXME: when we support something other than NTSC, we are going to
have to make the au0828 bridge adjust the size of its capture
buffer, which is currently hardcoded at 720x480 */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
- dev->std_set_in_tuner_core = 1;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm);
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
+
+ return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ *norm = dev->std;
return 0;
}
@@ -1368,10 +1412,13 @@ static int vidioc_enum_input(struct file *file, void *priv,
input->index = tmp;
strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
- (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+ (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) {
input->type |= V4L2_INPUT_TYPE_TUNER;
- else
+ input->audioset = 1;
+ } else {
input->type |= V4L2_INPUT_TYPE_CAMERA;
+ input->audioset = 2;
+ }
input->std = dev->vdev->tvnorms;
@@ -1386,32 +1433,25 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+static void au0828_s_input(struct au0828_dev *dev, int index)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
int i;
- dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
- index);
- if (index >= AU0828_MAX_INPUT)
- return -EINVAL;
- if (AUVI_INPUT(index).type == 0)
- return -EINVAL;
- dev->ctrl_input = index;
-
switch (AUVI_INPUT(index).type) {
case AU0828_VMUX_SVIDEO:
dev->input_type = AU0828_VMUX_SVIDEO;
+ dev->ctrl_ainput = 1;
break;
case AU0828_VMUX_COMPOSITE:
dev->input_type = AU0828_VMUX_COMPOSITE;
+ dev->ctrl_ainput = 1;
break;
case AU0828_VMUX_TELEVISION:
dev->input_type = AU0828_VMUX_TELEVISION;
+ dev->ctrl_ainput = 0;
break;
default:
- dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+ dprintk(1, "unknown input type set [%d]\n",
AUVI_INPUT(index).type);
break;
}
@@ -1442,55 +1482,60 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
AUVI_INPUT(index).amux, 0, 0);
- return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- unsigned int index = a->index;
+ dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
+ index);
+ if (index >= AU0828_MAX_INPUT)
+ return -EINVAL;
+ if (AUVI_INPUT(index).type == 0)
+ return -EINVAL;
+ dev->ctrl_input = index;
+ au0828_s_input(dev, index);
+ return 0;
+}
+
+static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
+{
if (a->index > 1)
return -EINVAL;
- index = dev->ctrl_ainput;
- if (index == 0)
+ if (a->index == 0)
strcpy(a->name, "Television");
else
strcpy(a->name, "Line in");
a->capability = V4L2_AUDCAP_STEREO;
- a->index = index;
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- if (a->index != dev->ctrl_ainput)
- return -EINVAL;
- return 0;
-}
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ a->index = dev->ctrl_ainput;
+ if (a->index == 0)
+ strcpy(a->name, "Television");
+ else
+ strcpy(a->name, "Line in");
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+ a->capability = V4L2_AUDCAP_STEREO;
return 0;
-
}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+
+ if (a->index != dev->ctrl_ainput)
+ return -EINVAL;
return 0;
}
@@ -1503,12 +1548,16 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return -EINVAL;
strcpy(t->name, "Auvitek tuner");
+
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ i2c_gate_ctrl(dev, 0);
return 0;
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
@@ -1516,15 +1565,10 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;
- t->type = V4L2_TUNER_ANALOG_TV;
-
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
-
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
t->afc);
@@ -1539,40 +1583,31 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- freq->type = V4L2_TUNER_ANALOG_TV;
+ if (freq->tuner != 0)
+ return -EINVAL;
freq->frequency = dev->ctrl_freq;
return 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
+ struct v4l2_frequency new_freq = *freq;
if (freq->tuner != 0)
return -EINVAL;
- if (freq->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
-
- dev->ctrl_freq = freq->frequency;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
-
- if (dev->std_set_in_tuner_core == 0) {
- /* If we've never sent the standard in tuner core, do so now. We
- don't do this at device probe because we don't want to incur
- the cost of a firmware load */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
- dev->vdev->tvnorms);
- dev->std_set_in_tuner_core = 1;
- }
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
+ /* Get the actual set (and possibly clamped) frequency */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+ dev->ctrl_freq = new_freq.frequency;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
au0828_analog_stream_reset(dev);
@@ -1598,6 +1633,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
format->fmt.vbi.count[1] = dev->vbi_height;
format->fmt.vbi.start[0] = 21;
format->fmt.vbi.start[1] = 284;
+ memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
return 0;
}
@@ -1664,6 +1700,7 @@ static int vidioc_streamon(struct file *file, void *priv,
if (unlikely(!res_get(fh, get_ressource(fh))))
return -EBUSY;
+ au0828_init_tuner(dev);
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
au0828_analog_stream_enable(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
@@ -1756,7 +1793,7 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
@@ -1773,6 +1810,15 @@ static int vidioc_s_register(struct file *file, void *priv,
}
#endif
+static int vidioc_log_status(struct file *file, void *fh)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ v4l2_ctrl_log_status(file, fh);
+ v4l2_device_call_all(vdev->v4l2_dev, 0, core, log_status);
+ return 0;
+}
+
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
@@ -1872,7 +1918,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
@@ -1881,12 +1929,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
@@ -1898,6 +1944,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct video_device au0828_video_template = {
@@ -1905,7 +1954,6 @@ static const struct video_device au0828_video_template = {
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_NTSC_M,
- .current_norm = V4L2_STD_NTSC_M,
};
/**************************************************************************/
@@ -1972,7 +2020,12 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->field_size = dev->width * dev->height;
dev->frame_size = dev->field_size << 1;
dev->bytesperline = dev->width << 1;
+ dev->vbi_width = 720;
+ dev->vbi_height = 1;
dev->ctrl_ainput = 0;
+ dev->ctrl_freq = 960;
+ dev->std = V4L2_STD_NTSC_M;
+ au0828_s_input(dev, 0);
/* allocate and fill v4l2 video struct */
dev->vdev = video_device_alloc();
@@ -1991,14 +2044,16 @@ int au0828_analog_register(struct au0828_dev *dev,
/* Fill the video capture device struct */
*dev->vdev = au0828_video_template;
- dev->vdev->parent = &dev->usbdev->dev;
+ dev->vdev->v4l2_dev = &dev->v4l2_dev;
dev->vdev->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev->flags);
strcpy(dev->vdev->name, "au0828a video");
/* Setup the VBI device */
*dev->vbi_dev = au0828_video_template;
- dev->vbi_dev->parent = &dev->usbdev->dev;
+ dev->vbi_dev->v4l2_dev = &dev->v4l2_dev;
dev->vbi_dev->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vbi_dev->flags);
strcpy(dev->vbi_dev->name, "au0828a vbi");
/* Register the v4l2 device */
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index e579ff69ca4..ef1f57f22be 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -28,6 +28,8 @@
#include <linux/videodev2.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
/* DVB */
#include "demux.h"
@@ -118,6 +120,9 @@ enum au0828_dev_state {
};
struct au0828_fh {
+ /* must be the first field of this struct! */
+ struct v4l2_fh fh;
+
struct au0828_dev *dev;
unsigned int resources;
@@ -202,6 +207,7 @@ struct au0828_dev {
#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Analog */
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler v4l2_ctrl_hdl;
#endif
int users;
unsigned int resources; /* resources in use */
@@ -216,6 +222,7 @@ struct au0828_dev {
int vbi_width;
int vbi_height;
u32 vbi_read;
+ v4l2_std_id std;
u32 field_size;
u32 frame_size;
u32 bytesperline;
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 28688dbcb60..f548db8043d 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -34,11 +34,12 @@
#include <linux/vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/cx2341x.h>
+#include <media/tuner.h>
#include <linux/usb.h>
#include "cx231xx.h"
-/*#include "cx23885-ioctl.h"*/
#define CX231xx_FIRM_IMAGE_SIZE 376836
#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
@@ -75,9 +76,11 @@
static unsigned int mpegbufs = 8;
module_param(mpegbufs, int, 0644);
MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+
static unsigned int mpeglines = 128;
module_param(mpeglines, int, 0644);
MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+
static unsigned int mpeglinesize = 512;
module_param(mpeglinesize, int, 0644);
MODULE_PARM_DESC(mpeglinesize,
@@ -86,10 +89,10 @@ MODULE_PARM_DESC(mpeglinesize,
static unsigned int v4l_debug = 1;
module_param(v4l_debug, int, 0644);
MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
-struct cx231xx_dmaqueue *dma_qq;
+
#define dprintk(level, fmt, arg...)\
do { if (v4l_debug >= level) \
- printk(KERN_INFO "%s: " fmt, \
+ pr_info("%s: " fmt, \
(dev) ? dev->name : "cx231xx[?]", ## arg); \
} while (0)
@@ -131,11 +134,13 @@ static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
};
/* ------------------------------------------------------------------ */
+
enum cx231xx_capture_type {
CX231xx_MPEG_CAPTURE,
CX231xx_RAW_CAPTURE,
CX231xx_RAW_PASSTHRU_CAPTURE
};
+
enum cx231xx_capture_bits {
CX231xx_RAW_BITS_NONE = 0x00,
CX231xx_RAW_BITS_YUV_CAPTURE = 0x01,
@@ -144,33 +149,40 @@ enum cx231xx_capture_bits {
CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10
};
+
enum cx231xx_capture_end {
CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
CX231xx_END_NOW, /* stop immediately, no irq */
};
+
enum cx231xx_framerate {
CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */
};
+
enum cx231xx_stream_port {
CX231xx_OUTPUT_PORT_MEMORY,
CX231xx_OUTPUT_PORT_STREAMING,
CX231xx_OUTPUT_PORT_SERIAL
};
+
enum cx231xx_data_xfer_status {
CX231xx_MORE_BUFFERS_FOLLOW,
CX231xx_LAST_BUFFER,
};
+
enum cx231xx_picture_mask {
CX231xx_PICTURE_MASK_NONE,
CX231xx_PICTURE_MASK_I_FRAMES,
CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
};
+
enum cx231xx_vbi_mode_bits {
CX231xx_VBI_BITS_SLICED,
CX231xx_VBI_BITS_RAW,
};
+
enum cx231xx_vbi_insertion_bits {
CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
@@ -178,56 +190,69 @@ enum cx231xx_vbi_insertion_bits {
CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
};
+
enum cx231xx_dma_unit {
CX231xx_DMA_BYTES,
CX231xx_DMA_FRAMES,
};
+
enum cx231xx_dma_transfer_status_bits {
CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
};
+
enum cx231xx_pause {
CX231xx_PAUSE_ENCODING,
CX231xx_RESUME_ENCODING,
};
+
enum cx231xx_copyright {
CX231xx_COPYRIGHT_OFF,
CX231xx_COPYRIGHT_ON,
};
+
enum cx231xx_notification_type {
CX231xx_NOTIFICATION_REFRESH,
};
+
enum cx231xx_notification_status {
CX231xx_NOTIFICATION_OFF,
CX231xx_NOTIFICATION_ON,
};
+
enum cx231xx_notification_mailbox {
CX231xx_NOTIFICATION_NO_MAILBOX = -1,
};
+
enum cx231xx_field1_lines {
CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
};
+
enum cx231xx_field2_lines {
CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
};
+
enum cx231xx_custom_data_type {
CX231xx_CUSTOM_EXTENSION_USR_DATA,
CX231xx_CUSTOM_PRIVATE_PACKET,
};
+
enum cx231xx_mute {
CX231xx_UNMUTE,
CX231xx_MUTE,
};
+
enum cx231xx_mute_video_mask {
CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
};
+
enum cx231xx_mute_video_shift {
CX231xx_MUTE_VIDEO_V_SHIFT = 8,
CX231xx_MUTE_VIDEO_U_SHIFT = 16,
@@ -296,41 +321,43 @@ enum cx231xx_mute_video_shift {
#define CX23417_GPIO_MASK 0xFC0003FF
-static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
+
+static int set_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 value)
{
int status = 0;
u32 _gpio_direction = 0;
_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
- _gpio_direction = _gpio_direction|gpio_direction;
+ _gpio_direction = _gpio_direction | gpio_direction;
status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
(u8 *)&value, 4, 0, 0);
return status;
}
-static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
+
+static int get_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 *val_ptr)
{
int status = 0;
u32 _gpio_direction = 0;
_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
- _gpio_direction = _gpio_direction|gpio_direction;
+ _gpio_direction = _gpio_direction | gpio_direction;
status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
- (u8 *)pValue, 4, 0, 1);
+ (u8 *)val_ptr, 4, 0, 1);
return status;
}
-static int waitForMciComplete(struct cx231xx *dev)
+static int wait_for_mci_complete(struct cx231xx *dev)
{
u32 gpio;
- u32 gpio_driection = 0;
+ u32 gpio_direction = 0;
u8 count = 0;
- getITVCReg(dev, gpio_driection, &gpio);
+ get_itvc_reg(dev, gpio_direction, &gpio);
while (!(gpio&0x020000)) {
msleep(10);
- getITVCReg(dev, gpio_driection, &gpio);
+ get_itvc_reg(dev, gpio_direction, &gpio);
if (count++ > 100) {
dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
@@ -345,57 +372,57 @@ static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
u32 temp;
int status = 0;
- temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
- temp = temp<<10;
- status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE0 | ((value & 0x000000FF) << 8);
+ temp = temp << 10;
+ status = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
if (status < 0)
return status;
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 1;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE1 | (value & 0x0000FF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 2;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 3;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 0;*/
- temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x000000FF) << 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 1;*/
- temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0x0000FF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*Write that the mode is write.*/
temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
- return waitForMciComplete(dev);
+ return wait_for_mci_complete(dev);
}
static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
@@ -407,70 +434,68 @@ static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 1;*/
temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write that the mode is read;*/
temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*wait for the MIRDY line to be asserted ,
signalling that the read is done;*/
- ret = waitForMciComplete(dev);
+ ret = wait_for_mci_complete(dev);
/*switch the DATA- GPIO to input mode;*/
/*Read data byte 0;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) >> 18);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/* Read data byte 1;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) >> 10);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 2;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) >> 2);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 3;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) << 6);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
*value = return_value;
-
-
return ret;
}
@@ -481,59 +506,59 @@ static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
u32 temp;
int ret = 0;
- temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
temp = temp << 10;
- ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
if (ret < 0)
return ret;
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 1;*/
temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 2;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 3;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/* write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000) >> 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/* write address byte 1;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/* write address byte 0;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*wait for MIRDY line;*/
- waitForMciComplete(dev);
+ wait_for_mci_complete(dev);
return 0;
}
@@ -545,68 +570,68 @@ static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
int ret = 0;
/*write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
- ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
+ ((address & 0x003F0000) >> 8);
+ temp = temp << 10;
+ ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
if (ret < 0)
return ret;
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 1*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 0*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*Wait for MIRDY line*/
- ret = waitForMciComplete(dev);
+ ret = wait_for_mci_complete(dev);
/*Read data byte 3;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)<<6);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE3) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE3) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) << 6);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 2;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>2);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE2) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE2) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 2);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/* Read data byte 1;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>10);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE1) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE1) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 0;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>18);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE0) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE0) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 18);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
*value = return_value;
return ret;
@@ -619,94 +644,91 @@ static char *cmd_to_str(int cmd)
{
switch (cmd) {
case CX2341X_ENC_PING_FW:
- return "PING_FW";
+ return "PING_FW";
case CX2341X_ENC_START_CAPTURE:
- return "START_CAPTURE";
+ return "START_CAPTURE";
case CX2341X_ENC_STOP_CAPTURE:
- return "STOP_CAPTURE";
+ return "STOP_CAPTURE";
case CX2341X_ENC_SET_AUDIO_ID:
- return "SET_AUDIO_ID";
+ return "SET_AUDIO_ID";
case CX2341X_ENC_SET_VIDEO_ID:
- return "SET_VIDEO_ID";
+ return "SET_VIDEO_ID";
case CX2341X_ENC_SET_PCR_ID:
- return "SET_PCR_PID";
+ return "SET_PCR_PID";
case CX2341X_ENC_SET_FRAME_RATE:
- return "SET_FRAME_RATE";
+ return "SET_FRAME_RATE";
case CX2341X_ENC_SET_FRAME_SIZE:
- return "SET_FRAME_SIZE";
+ return "SET_FRAME_SIZE";
case CX2341X_ENC_SET_BIT_RATE:
- return "SET_BIT_RATE";
+ return "SET_BIT_RATE";
case CX2341X_ENC_SET_GOP_PROPERTIES:
- return "SET_GOP_PROPERTIES";
+ return "SET_GOP_PROPERTIES";
case CX2341X_ENC_SET_ASPECT_RATIO:
- return "SET_ASPECT_RATIO";
+ return "SET_ASPECT_RATIO";
case CX2341X_ENC_SET_DNR_FILTER_MODE:
- return "SET_DNR_FILTER_PROPS";
+ return "SET_DNR_FILTER_PROPS";
case CX2341X_ENC_SET_DNR_FILTER_PROPS:
- return "SET_DNR_FILTER_PROPS";
+ return "SET_DNR_FILTER_PROPS";
case CX2341X_ENC_SET_CORING_LEVELS:
- return "SET_CORING_LEVELS";
+ return "SET_CORING_LEVELS";
case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
- return "SET_SPATIAL_FILTER_TYPE";
+ return "SET_SPATIAL_FILTER_TYPE";
case CX2341X_ENC_SET_VBI_LINE:
- return "SET_VBI_LINE";
+ return "SET_VBI_LINE";
case CX2341X_ENC_SET_STREAM_TYPE:
- return "SET_STREAM_TYPE";
+ return "SET_STREAM_TYPE";
case CX2341X_ENC_SET_OUTPUT_PORT:
- return "SET_OUTPUT_PORT";
+ return "SET_OUTPUT_PORT";
case CX2341X_ENC_SET_AUDIO_PROPERTIES:
- return "SET_AUDIO_PROPERTIES";
+ return "SET_AUDIO_PROPERTIES";
case CX2341X_ENC_HALT_FW:
- return "HALT_FW";
+ return "HALT_FW";
case CX2341X_ENC_GET_VERSION:
- return "GET_VERSION";
+ return "GET_VERSION";
case CX2341X_ENC_SET_GOP_CLOSURE:
- return "SET_GOP_CLOSURE";
+ return "SET_GOP_CLOSURE";
case CX2341X_ENC_GET_SEQ_END:
- return "GET_SEQ_END";
+ return "GET_SEQ_END";
case CX2341X_ENC_SET_PGM_INDEX_INFO:
- return "SET_PGM_INDEX_INFO";
+ return "SET_PGM_INDEX_INFO";
case CX2341X_ENC_SET_VBI_CONFIG:
- return "SET_VBI_CONFIG";
+ return "SET_VBI_CONFIG";
case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
- return "SET_DMA_BLOCK_SIZE";
+ return "SET_DMA_BLOCK_SIZE";
case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
- return "GET_PREV_DMA_INFO_MB_10";
+ return "GET_PREV_DMA_INFO_MB_10";
case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
- return "GET_PREV_DMA_INFO_MB_9";
+ return "GET_PREV_DMA_INFO_MB_9";
case CX2341X_ENC_SCHED_DMA_TO_HOST:
- return "SCHED_DMA_TO_HOST";
+ return "SCHED_DMA_TO_HOST";
case CX2341X_ENC_INITIALIZE_INPUT:
- return "INITIALIZE_INPUT";
+ return "INITIALIZE_INPUT";
case CX2341X_ENC_SET_FRAME_DROP_RATE:
- return "SET_FRAME_DROP_RATE";
+ return "SET_FRAME_DROP_RATE";
case CX2341X_ENC_PAUSE_ENCODER:
- return "PAUSE_ENCODER";
+ return "PAUSE_ENCODER";
case CX2341X_ENC_REFRESH_INPUT:
- return "REFRESH_INPUT";
+ return "REFRESH_INPUT";
case CX2341X_ENC_SET_COPYRIGHT:
- return "SET_COPYRIGHT";
+ return "SET_COPYRIGHT";
case CX2341X_ENC_SET_EVENT_NOTIFICATION:
- return "SET_EVENT_NOTIFICATION";
+ return "SET_EVENT_NOTIFICATION";
case CX2341X_ENC_SET_NUM_VSYNC_LINES:
- return "SET_NUM_VSYNC_LINES";
+ return "SET_NUM_VSYNC_LINES";
case CX2341X_ENC_SET_PLACEHOLDER:
- return "SET_PLACEHOLDER";
+ return "SET_PLACEHOLDER";
case CX2341X_ENC_MUTE_VIDEO:
- return "MUTE_VIDEO";
+ return "MUTE_VIDEO";
case CX2341X_ENC_MUTE_AUDIO:
- return "MUTE_AUDIO";
+ return "MUTE_AUDIO";
case CX2341X_ENC_MISC:
- return "MISC";
+ return "MISC";
default:
return "UNKNOWN";
}
}
-static int cx231xx_mbox_func(void *priv,
- u32 command,
- int in,
- int out,
+static int cx231xx_mbox_func(void *priv, u32 command, int in, int out,
u32 data[CX2341X_MBOX_MAX_DATA])
{
struct cx231xx *dev = priv;
@@ -721,11 +743,9 @@ static int cx231xx_mbox_func(void *priv,
without side effects */
mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
if (value != 0x12345678) {
- dprintk(3,
- "Firmware and/or mailbox pointer not initialized "
- "or corrupted, signature = 0x%x, cmd = %s\n", value,
- cmd_to_str(command));
- return -1;
+ dprintk(3, "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n",
+ value, cmd_to_str(command));
+ return -EIO;
}
/* This read looks at 32 bits, but flag is only 8 bits.
@@ -733,9 +753,9 @@ static int cx231xx_mbox_func(void *priv,
*/
mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
if (flag) {
- dprintk(3, "ERROR: Mailbox appears to be in use "
- "(%x), cmd = %s\n", flag, cmd_to_str(command));
- return -1;
+ dprintk(3, "ERROR: Mailbox appears to be in use (%x), cmd = %s\n",
+ flag, cmd_to_str(command));
+ return -EBUSY;
}
flag |= 1; /* tell 'em we're working on it */
@@ -764,7 +784,7 @@ static int cx231xx_mbox_func(void *priv,
break;
if (time_after(jiffies, timeout)) {
dprintk(3, "ERROR: API Mailbox timeout\n");
- return -1;
+ return -EIO;
}
udelay(10);
}
@@ -781,17 +801,14 @@ static int cx231xx_mbox_func(void *priv,
flag = 0;
mc417_memory_write(dev, dev->cx23417_mailbox, flag);
- return retval;
+ return 0;
}
/* We don't need to call the API often, so using just one
* mailbox will probably suffice
*/
-static int cx231xx_api_cmd(struct cx231xx *dev,
- u32 command,
- u32 inputcnt,
- u32 outputcnt,
- ...)
+static int cx231xx_api_cmd(struct cx231xx *dev, u32 command,
+ u32 inputcnt, u32 outputcnt, ...)
{
u32 data[CX2341X_MBOX_MAX_DATA];
va_list vargs;
@@ -813,6 +830,7 @@ static int cx231xx_api_cmd(struct cx231xx *dev,
return err;
}
+
static int cx231xx_find_mailbox(struct cx231xx *dev)
{
u32 signature[4] = {
@@ -834,81 +852,80 @@ static int cx231xx_find_mailbox(struct cx231xx *dev)
else
signaturecnt = 0;
if (4 == signaturecnt) {
- dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
- return i+1;
+ dprintk(1, "Mailbox signature found at 0x%x\n", i + 1);
+ return i + 1;
}
}
dprintk(3, "Mailbox signature values not found!\n");
return -1;
}
-static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
+static void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value,
u32 *p_fw_image)
{
-
u32 temp = 0;
int i = 0;
- temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/*write data byte 1;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/*write data byte 2;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/*write data byte 3;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/* write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000) >> 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/* write address byte 1;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/* write address byte 0;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
@@ -971,8 +988,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
IVTV_REG_APU, 0);
if (retval != 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
- __func__);
+ pr_err("%s: Error with mc417_register_write\n", __func__);
return -1;
}
@@ -980,25 +996,21 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
&dev->udev->dev);
if (retval != 0) {
- printk(KERN_ERR
- "ERROR: Hotplug firmware request failed (%s).\n",
+ pr_err("ERROR: Hotplug firmware request failed (%s).\n",
CX231xx_FIRM_IMAGE_NAME);
- printk(KERN_ERR "Please fix your hotplug setup, the board will "
- "not work without firmware loaded!\n");
+ pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n");
return -1;
}
if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
- printk(KERN_ERR "ERROR: Firmware size mismatch "
- "(have %zd, expected %d)\n",
+ pr_err("ERROR: Firmware size mismatch (have %zd, expected %d)\n",
firmware->size, CX231xx_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
}
if (0 != memcmp(firmware->data, magic, 8)) {
- printk(KERN_ERR
- "ERROR: Firmware magic mismatch, wrong file?\n");
+ pr_err("ERROR: Firmware magic mismatch, wrong file?\n");
release_firmware(firmware);
return -1;
}
@@ -1013,7 +1025,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
transfer_size += 4) {
fw_data = *p_fw_data;
- mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
+ mci_write_memory_to_gpio(dev, address, fw_data, p_current_fw);
address = address + 1;
p_current_fw += 20;
p_fw_data += 1;
@@ -1045,7 +1057,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
IVTV_CMD_HW_BLOCKS_RST);
if (retval < 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ pr_err("%s: Error with mc417_register_write\n",
__func__);
return retval;
}
@@ -1057,7 +1069,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
if (retval < 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ pr_err("%s: Error with mc417_register_write\n",
__func__);
return retval;
}
@@ -1082,10 +1094,10 @@ static void cx231xx_codec_settings(struct cx231xx *dev)
cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
dev->ts1.height, dev->ts1.width);
- dev->mpeg_params.width = dev->ts1.width;
- dev->mpeg_params.height = dev->ts1.height;
+ dev->mpeg_ctrl_handler.width = dev->ts1.width;
+ dev->mpeg_ctrl_handler.height = dev->ts1.height;
- cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
+ cx2341x_handler_setup(&dev->mpeg_ctrl_handler);
cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
@@ -1105,27 +1117,25 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
dprintk(2, "%s() PING OK\n", __func__);
retval = cx231xx_load_firmware(dev);
if (retval < 0) {
- printk(KERN_ERR "%s() f/w load failed\n", __func__);
+ pr_err("%s() f/w load failed\n", __func__);
return retval;
}
retval = cx231xx_find_mailbox(dev);
if (retval < 0) {
- printk(KERN_ERR "%s() mailbox < 0, error\n",
+ pr_err("%s() mailbox < 0, error\n",
__func__);
return -1;
}
dev->cx23417_mailbox = retval;
retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
if (retval < 0) {
- printk(KERN_ERR
- "ERROR: cx23417 firmware ping failed!\n");
+ pr_err("ERROR: cx23417 firmware ping failed!\n");
return -1;
}
retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
&version);
if (retval < 0) {
- printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
- "version failed!\n");
+ pr_err("ERROR: cx23417 firmware get encoder: version failed!\n");
return -1;
}
dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
@@ -1134,7 +1144,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
for (i = 0; i < 1; i++) {
retval = mc417_register_read(dev, 0x20f8, &val);
- dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
+ dprintk(3, "***before enable656() VIM Capture Lines = %d ***\n",
val);
if (retval < 0)
return retval;
@@ -1202,7 +1212,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
for (i = 0; i < 1; i++) {
mc417_register_read(dev, 0x20f8, &val);
- dprintk(3, "***VIM Capture Lines =%d ***\n", val);
+ dprintk(3, "***VIM Capture Lines =%d ***\n", val);
}
return 0;
@@ -1223,6 +1233,7 @@ static int bb_buf_setup(struct videobuf_queue *q,
return 0;
}
+
static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
{
struct cx231xx_fh *fh = vq->priv_data;
@@ -1249,91 +1260,85 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
struct cx231xx_dmaqueue *dma_q)
{
- void *vbuf;
- struct cx231xx_buffer *buf;
- u32 tail_data = 0;
- char *p_data;
-
- if (dma_q->mpeg_buffer_done == 0) {
- if (list_empty(&dma_q->active))
- return;
-
- buf = list_entry(dma_q->active.next,
- struct cx231xx_buffer, vb.queue);
- dev->video_mode.isoc_ctl.buf = buf;
- dma_q->mpeg_buffer_done = 1;
- }
- /* Fill buffer */
- buf = dev->video_mode.isoc_ctl.buf;
- vbuf = videobuf_to_vmalloc(&buf->vb);
-
- if ((dma_q->mpeg_buffer_completed+len) <
- mpeglines*mpeglinesize) {
- if (dma_q->add_ps_package_head ==
- CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
- memcpy(vbuf+dma_q->mpeg_buffer_completed,
- dma_q->ps_head, 3);
- dma_q->mpeg_buffer_completed =
- dma_q->mpeg_buffer_completed + 3;
- dma_q->add_ps_package_head =
- CX231XX_NONEED_PS_PACKAGE_HEAD;
- }
- memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
- dma_q->mpeg_buffer_completed =
- dma_q->mpeg_buffer_completed + len;
- } else {
- dma_q->mpeg_buffer_done = 0;
-
- tail_data =
- mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
- memcpy(vbuf+dma_q->mpeg_buffer_completed,
- data, tail_data);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- v4l2_get_timestamp(&buf->vb.ts);
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- dma_q->mpeg_buffer_completed = 0;
-
- if (len - tail_data > 0) {
- p_data = data + tail_data;
- dma_q->left_data_count = len - tail_data;
- memcpy(dma_q->p_left_data,
- p_data, len - tail_data);
- }
-
- }
-
- return;
-}
-
-static void buffer_filled(char *data, int len, struct urb *urb,
- struct cx231xx_dmaqueue *dma_q)
-{
- void *vbuf;
- struct cx231xx_buffer *buf;
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+ u32 tail_data = 0;
+ char *p_data;
+ if (dma_q->mpeg_buffer_done == 0) {
if (list_empty(&dma_q->active))
return;
-
buf = list_entry(dma_q->active.next,
- struct cx231xx_buffer, vb.queue);
+ struct cx231xx_buffer, vb.queue);
+ dev->video_mode.isoc_ctl.buf = buf;
+ dma_q->mpeg_buffer_done = 1;
+ }
+ /* Fill buffer */
+ buf = dev->video_mode.isoc_ctl.buf;
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+
+ if ((dma_q->mpeg_buffer_completed+len) <
+ mpeglines*mpeglinesize) {
+ if (dma_q->add_ps_package_head ==
+ CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ dma_q->ps_head, 3);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + 3;
+ dma_q->add_ps_package_head =
+ CX231XX_NONEED_PS_PACKAGE_HEAD;
+ }
+ memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + len;
+ } else {
+ dma_q->mpeg_buffer_done = 0;
+ tail_data =
+ mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ data, tail_data);
- /* Fill buffer */
- vbuf = videobuf_to_vmalloc(&buf->vb);
- memcpy(vbuf, data, len);
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
v4l2_get_timestamp(&buf->vb.ts);
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
+ dma_q->mpeg_buffer_completed = 0;
- return;
+ if (len - tail_data > 0) {
+ p_data = data + tail_data;
+ dma_q->left_data_count = len - tail_data;
+ memcpy(dma_q->p_left_data,
+ p_data, len - tail_data);
+ }
+ }
}
-static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+
+static void buffer_filled(char *data, int len, struct urb *urb,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+
+ if (list_empty(&dma_q->active))
+ return;
+
+ buf = list_entry(dma_q->active.next,
+ struct cx231xx_buffer, vb.queue);
+
+ /* Fill buffer */
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+ memcpy(vbuf, data, len);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ v4l2_get_timestamp(&buf->vb.ts);
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+static int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
{
struct cx231xx_dmaqueue *dma_q = urb->context;
unsigned char *p_buffer;
@@ -1358,11 +1363,9 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
return 0;
}
-static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
-{
- /*char *outp;*/
- /*struct cx231xx_buffer *buf;*/
+static int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
struct cx231xx_dmaqueue *dma_q = urb->context;
unsigned char *p_buffer, *buffer;
u32 buffer_size = 0;
@@ -1393,8 +1396,6 @@ static int bb_buf_prepare(struct videobuf_queue *q,
int rc = 0, urb_init = 0;
int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
- dma_qq = &dev->video_mode.vidq;
-
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
buf->vb.width = fh->dev->ts1.ts_packet_size;
@@ -1482,36 +1483,6 @@ static struct videobuf_queue_ops cx231xx_qops = {
/* ------------------------------------------------------------------ */
-static const u32 *ctrl_classes[] = {
- cx2341x_mpeg_ctrls,
- NULL
-};
-
-static int cx231xx_queryctrl(struct cx231xx *dev,
- struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
-
- /* MPEG V4L2 controls */
- if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-
- return 0;
-}
-
-static int cx231xx_querymenu(struct cx231xx *dev,
- struct v4l2_querymenu *qmenu)
-{
- struct v4l2_queryctrl qctrl;
-
- qctrl.id = qmenu->id;
- cx231xx_queryctrl(dev, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
-}
-
static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
{
struct cx231xx_fh *fh = file->private_data;
@@ -1520,14 +1491,15 @@ static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
*norm = dev->encodernorm.id;
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
- if (*id & cx231xx_tvnorms[i].id)
+ if (id & cx231xx_tvnorms[i].id)
break;
if (i == ARRAY_SIZE(cx231xx_tvnorms))
return -EINVAL;
@@ -1537,12 +1509,12 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
dprintk(3, "encodernorm set to NTSC\n");
dev->norm = V4L2_STD_NTSC;
dev->ts1.height = 480;
- dev->mpeg_params.is_50hz = 0;
+ cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
} else {
dprintk(3, "encodernorm set to PAL\n");
dev->norm = V4L2_STD_PAL_B;
dev->ts1.height = 576;
- dev->mpeg_params.is_50hz = 1;
+ cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true);
}
call_all(dev, core, s_std, dev->norm);
/* do mode control overrides */
@@ -1551,161 +1523,23 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
return 0;
}
-static int vidioc_g_audio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- struct v4l2_audio *vin = a;
-
- int ret = -EINVAL;
- if (vin->index > 0)
- return ret;
- strncpy(vin->name, "VideoGrabber Audio", 14);
- vin->capability = V4L2_AUDCAP_STEREO;
-return 0;
-}
-static int vidioc_enumaudio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- struct v4l2_audio *vin = a;
-
- int ret = -EINVAL;
-
- if (vin->index > 0)
- return ret;
- strncpy(vin->name, "VideoGrabber Audio", 14);
- vin->capability = V4L2_AUDCAP_STEREO;
-
-
-return 0;
-}
-static const char *iname[] = {
- [CX231XX_VMUX_COMPOSITE1] = "Composite1",
- [CX231XX_VMUX_SVIDEO] = "S-Video",
- [CX231XX_VMUX_TELEVISION] = "Television",
- [CX231XX_VMUX_CABLE] = "Cable TV",
- [CX231XX_VMUX_DVB] = "DVB",
- [CX231XX_VMUX_DEBUG] = "for debug only",
-};
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
- struct cx231xx_input *input;
- int n;
- dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
-
- if (i->index >= 4)
- return -EINVAL;
-
-
- input = &cx231xx_boards[dev->model].input[i->index];
-
- if (input->type == 0)
- return -EINVAL;
-
- /* FIXME
- * strcpy(i->name, input->name); */
-
- n = i->index;
- strcpy(i->name, iname[INPUT(n)->type]);
-
- if (input->type == CX231XX_VMUX_TELEVISION ||
- input->type == CX231XX_VMUX_CABLE)
- i->type = V4L2_INPUT_TYPE_TUNER;
- else
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
-
- dprintk(3, "enter vidioc_s_input() i=%d\n", i);
-
- mutex_lock(&dev->lock);
-
- video_mux(dev, i);
-
- mutex_unlock(&dev->lock);
-
- if (i >= 4)
- return -EINVAL;
- dev->input = i;
- dprintk(3, "exit vidioc_s_input()\n");
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
-
-
- return 0;
-}
static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctl)
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_s_ctrl()\n");
/* Update the A/V core */
call_all(dev, core, s_ctrl, ctl);
dprintk(3, "exit vidioc_s_ctrl()\n");
return 0;
}
-static struct v4l2_capability pvr_capability = {
- .driver = "cx231xx",
- .card = "VideoGrabber",
- .bus_info = "usb",
- .version = 1,
- .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
- V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
-};
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
-
-
-
- memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
- return 0;
-}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
-
if (f->index != 0)
return -EINVAL;
@@ -1720,17 +1554,18 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->ts1.width;
- f->fmt.pix.height = dev->ts1.height;
- f->fmt.pix.field = fh->vidq.field;
- dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
+ dev->ts1.width, dev->ts1.height);
dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
return 0;
}
@@ -1740,25 +1575,20 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+ dev->ts1.width, dev->ts1.height);
dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
return 0;
}
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
-
- return 0;
-}
-
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
@@ -1795,22 +1625,22 @@ static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type i)
{
struct cx231xx_fh *fh = file->private_data;
-
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_streamon()\n");
- cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
- cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
- if (dev->USE_ISO)
- cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
- CX231XX_NUM_BUFS,
- dev->video_mode.max_pkt_size,
- cx231xx_isoc_copy);
- else {
- cx231xx_init_bulk(dev, 320,
- 5,
- dev->ts1_mode.max_pkt_size,
- cx231xx_bulk_copy);
- }
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+ cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ if (dev->USE_ISO)
+ cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ else {
+ cx231xx_init_bulk(dev, 320,
+ 5,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ }
dprintk(3, "exit vidioc_streamon()\n");
return videobuf_streamon(&fh->vidq);
}
@@ -1822,117 +1652,25 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return videobuf_streamoff(&fh->vidq);
}
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_g_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- dprintk(3, "exit vidioc_g_ext_ctrls()\n");
- return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
- dprintk(3, "enter vidioc_s_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- if (err == 0) {
- err = cx2341x_update(dev, cx231xx_mbox_func,
- &dev->mpeg_params, &p);
- dev->mpeg_params = p;
- }
-
- return err;
-
-
-return 0;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
- dprintk(3, "enter vidioc_try_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
- return err;
-}
-
static int vidioc_log_status(struct file *file, void *priv)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- char name[32 + 2];
- snprintf(name, sizeof(name), "%s/2", dev->name);
- dprintk(3,
- "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
call_all(dev, core, log_status);
- cx2341x_log_status(&dev->mpeg_params, name);
- dprintk(3,
- "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_querymenu()\n");
- dprintk(3, "exit vidioc_querymenu()\n");
- return cx231xx_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_queryctrl()\n");
- dprintk(3, "exit vidioc_queryctrl()\n");
- return cx231xx_queryctrl(dev, c);
+ return v4l2_ctrl_log_status(file, priv);
}
static int mpeg_open(struct file *file)
{
- int minor = video_devdata(file)->minor;
- struct cx231xx *h, *dev = NULL;
- /*struct list_head *list;*/
+ struct video_device *vdev = video_devdata(file);
+ struct cx231xx *dev = video_drvdata(file);
struct cx231xx_fh *fh;
- /*u32 value = 0;*/
dprintk(2, "%s()\n", __func__);
- list_for_each_entry(h, &cx231xx_devlist, devlist) {
- if (h->v4l_device->minor == minor)
- dev = h;
- }
-
- if (dev == NULL)
- return -ENODEV;
-
- mutex_lock(&dev->lock);
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
@@ -1942,29 +1680,30 @@ static int mpeg_open(struct file *file)
}
file->private_data = fh;
- fh->dev = dev;
+ v4l2_fh_init(&fh->fh, vdev);
+ fh->dev = dev;
videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
NULL, &dev->video_mode.slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
- sizeof(struct cx231xx_buffer), fh, NULL);
+ sizeof(struct cx231xx_buffer), fh, &dev->lock);
/*
videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
&dev->udev->dev, &dev->ts1.slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx231xx_buffer),
- fh, NULL);
+ fh, &dev->lock);
*/
-
cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
cx231xx_set_gpio_value(dev, 2, 0);
cx231xx_initialize_codec(dev);
mutex_unlock(&dev->lock);
+ v4l2_fh_add(&fh->fh);
cx231xx_start_TS1(dev);
return 0;
@@ -1977,25 +1716,20 @@ static int mpeg_release(struct file *file)
dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
- if (!dev) {
- dprintk(3, "abort!!!\n");
- return 0;
- }
-
mutex_lock(&dev->lock);
cx231xx_stop_TS1(dev);
- /* do this before setting alternate! */
- if (dev->USE_ISO)
- cx231xx_uninit_isoc(dev);
- else
- cx231xx_uninit_bulk(dev);
- cx231xx_set_mode(dev, CX231XX_SUSPEND);
+ /* do this before setting alternate! */
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
- cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
- CX231xx_RAW_BITS_NONE);
+ cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
+ CX231xx_RAW_BITS_NONE);
/* FIXME: Review this crap */
/* Shut device down on last close */
@@ -2015,7 +1749,8 @@ static int mpeg_release(struct file *file)
videobuf_read_stop(&fh->vidq);
videobuf_mmap_free(&fh->vidq);
- file->private_data = NULL;
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
mutex_unlock(&dev->lock);
return 0;
@@ -2027,7 +1762,6 @@ static ssize_t mpeg_read(struct file *file, char __user *data,
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
-
/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
/* Start mpeg encoder on first read. */
if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
@@ -2044,12 +1778,23 @@ static ssize_t mpeg_read(struct file *file, char __user *data,
static unsigned int mpeg_poll(struct file *file,
struct poll_table_struct *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct cx231xx_fh *fh = file->private_data;
- /*struct cx231xx *dev = fh->dev;*/
+ struct cx231xx *dev = fh->dev;
+ unsigned int res = 0;
+
+ if (v4l2_event_pending(&fh->fh))
+ res |= POLLPRI;
+ else
+ poll_wait(file, &fh->fh.wait, wait);
- /*dprintk(2, "%s\n", __func__);*/
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return res;
- return videobuf_poll_stream(file, &fh->vidq, wait);
+ mutex_lock(&dev->lock);
+ res |= videobuf_poll_stream(file, &fh->vidq, wait);
+ mutex_unlock(&dev->lock);
+ return res;
}
static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
@@ -2069,44 +1814,39 @@ static struct v4l2_file_operations mpeg_fops = {
.read = mpeg_read,
.poll = mpeg_poll,
.mmap = mpeg_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_enumaudio = vidioc_enumaudio,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_tuner = cx231xx_g_tuner,
+ .vidioc_s_tuner = cx231xx_s_tuner,
+ .vidioc_g_frequency = cx231xx_g_frequency,
+ .vidioc_s_frequency = cx231xx_s_frequency,
+ .vidioc_enum_input = cx231xx_enum_input,
+ .vidioc_g_input = cx231xx_g_input,
+ .vidioc_s_input = cx231xx_s_input,
.vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_querycap = vidioc_querycap,
+ .vidioc_querycap = cx231xx_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
- .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
- .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
.vidioc_log_status = vidioc_log_status,
- .vidioc_querymenu = vidioc_querymenu,
- .vidioc_queryctrl = vidioc_queryctrl,
-/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/
+ .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
-/* .vidioc_g_register = cx231xx_g_register,*/
-/* .vidioc_s_register = cx231xx_s_register,*/
+ .vidioc_g_register = cx231xx_g_register,
+ .vidioc_s_register = cx231xx_s_register,
#endif
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device cx231xx_mpeg_template = {
@@ -2114,8 +1854,7 @@ static struct video_device cx231xx_mpeg_template = {
.fops = &mpeg_fops,
.ioctl_ops = &mpeg_ioctl_ops,
.minor = -1,
- .tvnorms = CX231xx_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
+ .tvnorms = V4L2_STD_ALL,
};
void cx231xx_417_unregister(struct cx231xx *dev)
@@ -2128,10 +1867,44 @@ void cx231xx_417_unregister(struct cx231xx *dev)
video_unregister_device(dev->v4l_device);
else
video_device_release(dev->v4l_device);
+ v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
dev->v4l_device = NULL;
}
}
+static int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
+{
+ struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
+ int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_mbus_framefmt fmt;
+
+ /* fix videodecoder resolution */
+ fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
+ fmt.height = cxhdl->height;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(dev->sd_cx25840, video, s_mbus_fmt, &fmt);
+ return 0;
+}
+
+static int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
+{
+ static const u32 freqs[3] = { 44100, 48000, 32000 };
+ struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
+
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (idx < ARRAY_SIZE(freqs))
+ call_all(dev, audio, s_clock_freq, freqs[idx]);
+ return 0;
+}
+
+static struct cx2341x_handler_ops cx231xx_ops = {
+ /* needed for the video clock freq */
+ .s_audio_sampling_freq = cx231xx_s_audio_sampling_freq,
+ /* needed for setting up the video resolution */
+ .s_video_encoding = cx231xx_s_video_encoding,
+};
+
static struct video_device *cx231xx_video_dev_alloc(
struct cx231xx *dev,
struct usb_device *usbdev,
@@ -2145,12 +1918,21 @@ static struct video_device *cx231xx_video_dev_alloc(
if (NULL == vfd)
return NULL;
*vfd = *template;
- vfd->minor = -1;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
type, cx231xx_boards[dev->model].name);
vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->lock = &dev->lock;
vfd->release = video_device_release;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl;
+ video_set_drvdata(vfd, dev);
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
+ }
return vfd;
@@ -2173,10 +1955,27 @@ int cx231xx_417_register(struct cx231xx *dev)
tsport->height = 576;
tsport->width = 720;
- cx2341x_fill_defaults(&dev->mpeg_params);
+ err = cx2341x_handler_init(&dev->mpeg_ctrl_handler, 50);
+ if (err) {
+ dprintk(3, "%s: can't init cx2341x controls\n", dev->name);
+ return err;
+ }
+ dev->mpeg_ctrl_handler.func = cx231xx_mbox_func;
+ dev->mpeg_ctrl_handler.priv = dev;
+ dev->mpeg_ctrl_handler.ops = &cx231xx_ops;
+ if (dev->sd_cx25840)
+ v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl,
+ dev->sd_cx25840->ctrl_handler, NULL);
+ if (dev->mpeg_ctrl_handler.hdl.error) {
+ err = dev->mpeg_ctrl_handler.hdl.error;
+ dprintk(3, "%s: can't add cx25840 controls\n", dev->name);
+ v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
+ return err;
+ }
dev->norm = V4L2_STD_NTSC;
- dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+ dev->mpeg_ctrl_handler.port = CX2341X_PORT_SERIAL;
+ cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
/* Allocate and initialize V4L video device */
dev->v4l_device = cx231xx_video_dev_alloc(dev,
@@ -2185,6 +1984,7 @@ int cx231xx_417_register(struct cx231xx *dev)
VFL_TYPE_GRABBER, -1);
if (err < 0) {
dprintk(3, "%s: can't register mpeg device\n", dev->name);
+ v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
return err;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index b4c99c7270c..81a1d971d79 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -449,9 +449,6 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
return -ENODEV;
}
- /* Sets volume, mute, etc */
- dev->mute = 0;
-
/* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */
mutex_lock(&dev->lock);
@@ -503,7 +500,6 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
return ret;
}
- dev->mute = 1;
dev->adev.users--;
mutex_unlock(&dev->lock);
@@ -708,8 +704,8 @@ static int cx231xx_audio_init(struct cx231xx *dev)
audio_index + 1];
adev->end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
adev->num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 72220791374..235ba657d52 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -357,6 +357,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
+ case CX231XX_BOARD_OTG102:
if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
FLD_PWRDN_ENABLE_PLL)) {
@@ -1720,6 +1721,7 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
case CX231XX_BOARD_CNXT_RDU_250:
case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_OTG102:
func_mode = 0x03;
break;
case CX231XX_BOARD_CNXT_RDE_253S:
@@ -2133,7 +2135,7 @@ int cx231xx_tuner_post_channel_change(struct cx231xx *dev)
status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
- return status;
+ return status == sizeof(dwval) ? 0 : -EIO;
}
/******************************************************************************
@@ -2221,7 +2223,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
switch (mode) {
case POLARIS_AVMODE_ENXTERNAL_AV:
@@ -2442,7 +2444,7 @@ int cx231xx_power_suspend(struct cx231xx *dev)
if (status > 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp &= (~PWR_MODE_MASK);
value[0] = (u8) tmp;
@@ -2470,7 +2472,7 @@ int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp |= ep_mask;
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
@@ -2495,7 +2497,7 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp &= (~ep_mask);
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
@@ -2638,20 +2640,23 @@ EXPORT_SYMBOL_GPL(cx231xx_capture_start);
/*****************************************************************************
* G P I O B I T control functions *
******************************************************************************/
-int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
+static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val)
{
int status = 0;
- status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 0);
+ gpio_val = cpu_to_le32(gpio_val);
+ status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&gpio_val, 4, 0, 0);
return status;
}
-int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
+static int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 *gpio_val)
{
+ u32 tmp;
int status = 0;
- status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 1);
+ status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&tmp, 4, 0, 1);
+ *gpio_val = le32_to_cpu(tmp);
return status;
}
@@ -2683,7 +2688,7 @@ int cx231xx_set_gpio_direction(struct cx231xx *dev,
else
value = dev->gpio_dir | (1 << pin_number);
- status = cx231xx_set_gpio_bit(dev, value, (u8 *) &dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, value, dev->gpio_val);
/* cache the value for future */
dev->gpio_dir = value;
@@ -2717,7 +2722,7 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value)
value = dev->gpio_dir | (1 << pin_number);
dev->gpio_dir = value;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *) &dev->gpio_val);
+ dev->gpio_val);
value = 0;
}
@@ -2730,7 +2735,7 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value)
dev->gpio_val = value;
/* toggle bit0 of GP_IO */
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
@@ -2748,7 +2753,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev)
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2756,7 +2761,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev)
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2764,7 +2769,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev)
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2782,7 +2787,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev)
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2790,7 +2795,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev)
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2800,7 +2805,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev)
dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
status =
- cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2822,33 +2827,33 @@ int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data)
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 1; set SDA to output 0 */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 0; set SDA to output 0 */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
} else {
/* set SCL to output 0; set SDA to output 1 */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 1; set SDA to output 1 */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 0; set SDA to output 1 */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
}
}
return status;
@@ -2867,17 +2872,17 @@ int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf)
/* set SCL to output 0; set SDA to input */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 1; set SDA to input */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* get SDA data bit */
gpio_logic_value = dev->gpio_val;
status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ &dev->gpio_val);
if ((dev->gpio_val & (1 << dev->board.tuner_sda_gpio)) != 0)
value |= (1 << (8 - i - 1));
@@ -2888,7 +2893,7 @@ int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf)
!!!set SDA to input, never to modify SDA direction at
the same times */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* store the value */
*buf = value & 0xff;
@@ -2909,12 +2914,12 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio);
gpio_logic_value = dev->gpio_val;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
do {
msleep(2);
status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ &dev->gpio_val);
nCnt--;
} while (((dev->gpio_val &
(1 << dev->board.tuner_scl_gpio)) == 0) &&
@@ -2929,7 +2934,7 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
* through clock stretch, slave has given a SCL signal,
* so the SDA data can be directly read.
*/
- status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, &dev->gpio_val);
if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) {
dev->gpio_val = gpio_logic_value;
@@ -2945,7 +2950,7 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
dev->gpio_val = gpio_logic_value;
dev->gpio_dir |= (1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
@@ -2956,24 +2961,24 @@ int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev)
/* set SDA to ouput */
dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SCL = 0 (output); set SDA = 0 (output) */
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SCL = 1 (output); set SDA = 0 (output) */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SCL = 0 (output); set SDA = 0 (output) */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SDA to input,and then the slave will read data from SDA. */
dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
@@ -2985,15 +2990,15 @@ int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev)
/* set scl to output ; set sda to input */
dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set scl to output 0; set sda to input */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set scl to output 1; set sda to input */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 8d529565f16..13249e5a789 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -263,7 +263,11 @@ struct cx231xx_board cx231xx_boards[] = {
.norm = V4L2_STD_PAL,
.no_alt_vanc = 1,
.external_av = 1,
- .has_417 = 1,
+ .dont_use_port_3 = 1,
+ /* Actually, it has a 417, but it isn't working correctly.
+ * So set to 0 for now until someone can manage to get this
+ * to work reliably. */
+ .has_417 = 0,
.input = {{
.type = CX231XX_VMUX_COMPOSITE1,
@@ -630,6 +634,39 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_OTG102] = {
+ .name = "Geniatech OTG102",
+ .tuner_type = TUNER_ABSENT,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ /* According with PV CxPlrCAP.inf file */
+ .gpio_pin_status_mask = 0x4001000,
+ .norm = V4L2_STD_NTSC,
+ .no_alt_vanc = 1,
+ .external_av = 1,
+ .dont_use_port_3 = 1,
+ /*.has_417 = 1, */
+ /* This board is believed to have a hardware encoding chip
+ * supporting mpeg1/2/4, but as the 417 is apparently not
+ * working for the reference board it is not here either. */
+
+ .input = {{
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }
+ },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -671,6 +708,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_ICONBIT_U100},
{USB_DEVICE(0x0fd9, 0x0037),
.driver_info = CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2},
+ {USB_DEVICE(0x1f4d, 0x0102),
+ .driver_info = CX231XX_BOARD_OTG102},
{},
};
@@ -846,8 +885,6 @@ void cx231xx_card_setup(struct cx231xx *dev)
int cx231xx_config(struct cx231xx *dev)
{
/* TBD need to add cx231xx specific code */
- dev->mute = 1; /* maybe not the right place... */
- dev->volume = 0x1f;
return 0;
}
@@ -1187,8 +1224,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
uif = udev->actconfig->interface[dev->current_pcb_config.
hs_config_info[0].interface_info.video_index + 1];
- dev->video_mode.end_point_addr = le16_to_cpu(uif->altsetting[0].
- endpoint[isoc_pipe].desc.bEndpointAddress);
+ dev->video_mode.end_point_addr = uif->altsetting[0].
+ endpoint[isoc_pipe].desc.bEndpointAddress;
dev->video_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
@@ -1221,8 +1258,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
vanc_index + 1];
dev->vbi_mode.end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
dev->vbi_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
@@ -1256,8 +1293,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
hanc_index + 1];
dev->sliced_cc_mode.end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
dev->sliced_cc_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
@@ -1292,8 +1329,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
ts1_index + 1];
dev->ts1_mode.end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].
- desc.bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].
+ desc.bEndpointAddress;
dev->ts1_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 05358d48613..4ba3ce09b71 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1488,7 +1488,7 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp |= mode;
value[0] = (u8) tmp;
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 7c4e360ba9b..14e26106fd7 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -89,8 +89,8 @@ static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
};
static struct tda18271_std_map mb86a20s_tda18271_config = {
- .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
- .if_lvl = 7, .rfagc_top = 0x37, },
+ .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
+ .if_lvl = 0, .rfagc_top = 0x37, },
};
static struct tda18271_config cnxt_rde253s_tunerconfig = {
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
index 7473c33e823..d7308ab7a90 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
@@ -672,7 +672,7 @@ u32 initialize_cx231xx(struct cx231xx *dev)
pcb config it is related to */
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4);
- config_info = *((u32 *) data);
+ config_info = le32_to_cpu(*((u32 *) data));
usb_speed = (u8) (config_info & 0x1);
/* Verify this device belongs to Bus power or Self power device */
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
index f5e46e89f3a..b3c6190e0c6 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
@@ -68,11 +68,6 @@ enum USB_SPEED{
HIGH_SPEED = 0x1 /* 1: high speed */
};
-enum _true_false{
- FALSE = 0,
- TRUE = 1
-};
-
#define TS_MASK 0x6
enum TS_PORT{
NO_TS_PORT = 0x0, /* 2'b00: Neither port used. PCB not a Hybrid,
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index 46e3892557c..1340ff26881 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -70,10 +70,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
break;
}
if (packet < 0) {
- cx231xx_err(DRIVER_NAME "URB status %d [%s].\n", status,
+ cx231xx_err("URB status %d [%s].\n", status,
errmsg);
} else {
- cx231xx_err(DRIVER_NAME "URB packet %d, status %d [%s].\n",
+ cx231xx_err("URB packet %d, status %d [%s].\n",
packet, status, errmsg);
}
}
@@ -317,7 +317,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- cx231xx_err(DRIVER_NAME "urb completition error %d.\n",
+ cx231xx_err("urb completition error %d.\n",
urb->status);
break;
}
@@ -332,7 +332,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
if (urb->status) {
- cx231xx_err(DRIVER_NAME "urb resubmit failed (error=%i)\n",
+ cx231xx_err("urb resubmit failed (error=%i)\n",
urb->status);
}
}
@@ -345,7 +345,7 @@ void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
struct urb *urb;
int i;
- cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n");
+ cx231xx_info("called cx231xx_uninit_vbi_isoc\n");
dev->vbi_mode.bulk_ctl.nfields = -1;
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
@@ -394,7 +394,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
struct urb *urb;
int rc;
- cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_prepare_isoc\n");
+ cx231xx_info("called cx231xx_vbi_isoc\n");
/* De-allocates all pending stuff */
cx231xx_uninit_vbi_isoc(dev);
@@ -442,8 +442,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- cx231xx_err(DRIVER_NAME
- ": cannot alloc bulk_ctl.urb %i\n", i);
+ cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
cx231xx_uninit_vbi_isoc(dev);
return -ENOMEM;
}
@@ -453,8 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
kzalloc(sb_size, GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
- cx231xx_err(DRIVER_NAME
- ": unable to allocate %i bytes for transfer"
+ cx231xx_err("unable to allocate %i bytes for transfer"
" buffer %i%s\n", sb_size, i,
in_interrupt() ? " while in int" : "");
cx231xx_uninit_vbi_isoc(dev);
@@ -473,8 +471,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC);
if (rc) {
- cx231xx_err(DRIVER_NAME
- ": submit of urb %i failed (error=%i)\n", i,
+ cx231xx_err("submit of urb %i failed (error=%i)\n", i,
rc);
cx231xx_uninit_vbi_isoc(dev);
return rc;
@@ -526,7 +523,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev,
struct cx231xx_buffer *buf)
{
/* Advice that buffer was filled */
- /* cx231xx_info(DRIVER_NAME "[%p/%d] wakeup\n", buf, buf->vb.i); */
+ /* cx231xx_info("[%p/%d] wakeup\n", buf, buf->vb.i); */
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
@@ -618,7 +615,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
char *outp;
if (list_empty(&dma_q->active)) {
- cx231xx_err(DRIVER_NAME ": No active queue to serve\n");
+ cx231xx_err("No active queue to serve\n");
dev->vbi_mode.bulk_ctl.buf = NULL;
*buf = NULL;
return;
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 06376d904c9..cd221474e1b 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -35,6 +35,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-chip-ident.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -100,125 +101,6 @@ static struct cx231xx_fmt format[] = {
},
};
-/* supported controls */
-/* Common to all boards */
-
-/* ------------------------------------------------------------------- */
-
-static const struct v4l2_queryctrl no_ctl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct cx231xx_ctrl cx231xx_ctls[] = {
- /* --- video --- */
- {
- .v = {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = LUMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- .v = {
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = LUMA_CTRL,
- .mask = 0xff00,
- .shift = 8,
- }, {
- .v = {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = CHROMA_CTRL,
- .mask = 0xff0000,
- .shift = 16,
- }, {
- /* strictly, this only describes only U saturation.
- * V saturation is handled specially through code.
- */
- .v = {
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = CHROMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- /* --- audio --- */
- .v = {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
- .reg = PATH1_CTL1,
- .mask = (0x1f << 24),
- .shift = 24,
- }, {
- .v = {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 0x3f,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .reg = PATH1_VOL_CTL,
- .mask = 0xff,
- .shift = 0,
- }
-};
-static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls);
-
-static const u32 cx231xx_user_ctrls[] = {
- V4L2_CID_USER_CLASS,
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_AUDIO_VOLUME,
-#if 0
- V4L2_CID_AUDIO_BALANCE,
-#endif
- V4L2_CID_AUDIO_MUTE,
- 0
-};
-
-static const u32 *ctrl_classes[] = {
- cx231xx_user_ctrls,
- NULL
-};
/* ------------------------------------------------------------------
Video buffer and parser functions
@@ -1005,6 +887,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1045,10 +928,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = width;
f->fmt.pix.height = height;
f->fmt.pix.pixelformat = fmt->fourcc;
- f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1103,39 +987,39 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
struct v4l2_mbus_framefmt mbus_fmt;
- struct v4l2_format f;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
+ if (dev->norm == norm)
+ return 0;
- dev->norm = *norm;
+ if (videobuf_queue_is_busy(&fh->vb_vidq))
+ return -EBUSY;
+
+ dev->norm = norm;
/* Adjusts width/height, if needed */
- f.fmt.pix.width = dev->width;
- f.fmt.pix.height = dev->height;
- vidioc_try_fmt_vid_cap(file, priv, &f);
+ dev->width = 720;
+ dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480;
call_all(dev, core, s_std, dev->norm);
/* We need to reset basic properties in the decoder related to
resolution (since a standard change effects things like the number
of lines in VACT, etc) */
- v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED);
+ memset(&mbus_fmt, 0, sizeof(mbus_fmt));
+ mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ mbus_fmt.width = dev->width;
+ mbus_fmt.height = dev->height;
call_all(dev, video, s_mbus_fmt, &mbus_fmt);
- v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt);
-
- /* set new image size */
- dev->width = f.fmt.pix.width;
- dev->height = f.fmt.pix.height;
/* do mode control overrides */
cx231xx_do_mode_ctrl_overrides(dev);
@@ -1152,7 +1036,7 @@ static const char *iname[] = {
[CX231XX_VMUX_DEBUG] = "for debug only",
};
-static int vidioc_enum_input(struct file *file, void *priv,
+int cx231xx_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
struct cx231xx_fh *fh = priv;
@@ -1192,7 +1076,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+int cx231xx_g_input(struct file *file, void *priv, unsigned int *i)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1202,7 +1086,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1231,117 +1115,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- switch (a->index) {
- case CX231XX_AMUX_VIDEO:
- strcpy(a->name, "Television");
- break;
- case CX231XX_AMUX_LINE_IN:
- strcpy(a->name, "Line In");
- break;
- default:
- return -EINVAL;
- }
-
- a->index = dev->ctl_ainput;
- a->capability = V4L2_AUDCAP_STEREO;
-
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int status = 0;
-
- /* Doesn't allow manual routing */
- if (a->index != dev->ctl_ainput)
- return -EINVAL;
-
- dev->ctl_ainput = INPUT(a->index)->amux;
- status = cx231xx_set_audio_input(dev, dev->ctl_ainput);
-
- return status;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int id = qc->id;
- int i;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
- if (unlikely(qc->id == 0))
- return -EINVAL;
-
- memset(qc, 0, sizeof(*qc));
-
- qc->id = id;
-
- if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1)
- return -EINVAL;
-
- for (i = 0; i < CX231XX_CTLS; i++)
- if (cx231xx_ctls[i].v.id == qc->id)
- break;
-
- if (i == CX231XX_CTLS) {
- *qc = no_ctl;
- return 0;
- }
- *qc = cx231xx_ctls[i].v;
-
- call_all(dev, core, queryctrl, qc);
-
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, core, g_ctrl, ctrl);
- return rc;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, core, s_ctrl, ctrl);
- return rc;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1360,11 +1134,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
t->capability = V4L2_TUNER_CAP_NORM;
t->rangehigh = 0xffffffffUL;
t->signal = 0xffff; /* LOCKED */
+ call_all(dev, tuner, g_tuner, t);
return 0;
}
-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1382,25 +1157,26 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return 0;
}
-static int vidioc_g_frequency(struct file *file, void *priv,
+int cx231xx_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->ctl_freq;
+ if (f->tuner)
+ return -EINVAL;
- call_all(dev, tuner, g_frequency, f);
+ f->frequency = dev->ctl_freq;
return 0;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+int cx231xx_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
+ struct v4l2_frequency new_freq = *f;
int rc;
u32 if_frequency = 5400000;
@@ -1415,16 +1191,12 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (0 != f->tuner)
return -EINVAL;
- if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
- return -EINVAL;
- if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
- return -EINVAL;
-
/* set pre channel change settings in DIF first */
rc = cx231xx_tuner_pre_channel_change(dev);
- dev->ctl_freq = f->frequency;
call_all(dev, tuner, s_frequency, f);
+ call_all(dev, tuner, g_frequency, &new_freq);
+ dev->ctl_freq = new_freq.frequency;
/* set post channel change settings in DIF first */
rc = cx231xx_tuner_post_channel_change(dev);
@@ -1456,6 +1228,19 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return rc;
}
+int cx231xx_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(&chip->match))
+ chip->ident = V4L2_IDENT_CX23100;
+ return 0;
+ }
+ return -EINVAL;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
@@ -1471,7 +1256,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if type == i2caddr, then <chip> is the 7-bit I2C address
*/
-static int vidioc_g_register(struct file *file, void *priv,
+int cx231xx_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
struct cx231xx_fh *fh = priv;
@@ -1618,8 +1403,8 @@ static int vidioc_g_register(struct file *file, void *priv,
return ret;
}
-static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+int cx231xx_s_register(struct file *file, void *priv,
+ const struct v4l2_dbg_register *reg)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1837,9 +1622,6 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (rc < 0)
return rc;
- if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
if (type != fh->type)
return -EINVAL;
@@ -1851,9 +1633,10 @@ static int vidioc_streamoff(struct file *file, void *priv,
return 0;
}
-static int vidioc_querycap(struct file *file, void *priv,
+int cx231xx_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct video_device *vdev = video_devdata(file);
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1861,17 +1644,22 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VBI_CAPTURE |
-#if 0
- V4L2_CAP_SLICED_VBI_CAPTURE |
-#endif
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
+ cap->device_caps = V4L2_CAP_RADIO;
+ else {
+ cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (vdev->vfl_type == VFL_TYPE_VBI)
+ cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+ else
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ }
if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
+ cap->device_caps |= V4L2_CAP_TUNER;
+ cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE |
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
+ if (dev->radio_dev)
+ cap->capabilities |= V4L2_CAP_RADIO;
return 0;
}
@@ -1888,47 +1676,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-/* Sliced VBI ioctls */
-static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- f->fmt.sliced.service_set = 0;
-
- call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- rc = -EINVAL;
-
- return rc;
-}
-
-static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- return -EINVAL;
-
- return 0;
-}
-
/* RAW VBI ioctls */
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
@@ -1936,6 +1683,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
+
f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -1947,6 +1695,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+ memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
return 0;
@@ -1958,12 +1707,6 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- if (dev->vbi_stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
- return -EBUSY;
- }
-
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -1976,11 +1719,25 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+ memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
return 0;
}
+static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ if (dev->vbi_stream_on && !fh->stream_on) {
+ cx231xx_errdev("%s device in use by another fh\n", __func__);
+ return -EBUSY;
+ }
+ return vidioc_try_fmt_vbi_cap(file, priv, f);
+}
+
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
@@ -2038,58 +1795,24 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
-
- strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
- strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
-}
-
static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
- if (unlikely(t->index > 0))
+ if (t->index)
return -EINVAL;
strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
-
- call_all(dev, tuner, s_tuner, t);
-
- return 0;
-}
-static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
+ call_all(dev, tuner, g_tuner, t);
return 0;
}
-
-static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
{
struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
- if (0 != t->index)
+ if (t->index)
return -EINVAL;
call_all(dev, tuner, s_tuner, t);
@@ -2097,36 +1820,6 @@ static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return 0;
}
-static int radio_s_audio(struct file *file, void *fh, const struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int radio_s_input(struct file *file, void *fh, unsigned int i)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- int i;
-
- if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- for (i = 0; i < CX231XX_CTLS; i++) {
- if (cx231xx_ctls[i].v.id == c->id)
- break;
- }
- if (i == CX231XX_CTLS)
- return -EINVAL;
- *c = cx231xx_ctls[i].v;
- } else
- *c = no_ctl;
- return 0;
-}
-
/*
* cx231xx_v4l2_open()
* inits the device and starts isoc transfer
@@ -2174,14 +1867,11 @@ static int cx231xx_v4l2_open(struct file *filp)
return -ERESTARTSYS;
}
fh->dev = dev;
- fh->radio = radio;
fh->type = fh_type;
filp->private_data = fh;
+ v4l2_fh_init(&fh->fh, vdev);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
- dev->width = norm_maxw(dev);
- dev->height = norm_maxh(dev);
-
/* Power up in Analog TV mode */
if (dev->board.external_av)
cx231xx_set_power_mode(dev,
@@ -2204,7 +1894,7 @@ static int cx231xx_v4l2_open(struct file *filp)
dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
}
- if (fh->radio) {
+ if (radio) {
cx231xx_videodbg("video_open: setting radio device\n");
/* cx231xx_start_radio(dev); */
@@ -2232,6 +1922,7 @@ static int cx231xx_v4l2_open(struct file *filp)
fh, &dev->lock);
}
mutex_unlock(&dev->lock);
+ v4l2_fh_add(&fh->fh);
return errCode;
}
@@ -2275,6 +1966,8 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
video_device_release(dev->vdev);
dev->vdev = NULL;
}
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
}
/*
@@ -2324,12 +2017,15 @@ static int cx231xx_close(struct file *filp)
else
cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
return 0;
}
+ v4l2_fh_del(&fh->fh);
dev->users--;
if (!dev->users) {
videobuf_stop(&fh->vb_vidq);
@@ -2356,6 +2052,7 @@ static int cx231xx_close(struct file *filp)
/* set alternate 0 */
cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
}
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
wake_up_interruptible_nr(&dev->open, 1);
return 0;
@@ -2412,29 +2109,37 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
*/
static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct cx231xx_fh *fh = filp->private_data;
struct cx231xx *dev = fh->dev;
+ unsigned res = 0;
int rc;
rc = check_dev(dev);
if (rc < 0)
- return rc;
+ return POLLERR;
rc = res_get(fh);
if (unlikely(rc < 0))
return POLLERR;
+ if (v4l2_event_pending(&fh->fh))
+ res |= POLLPRI;
+ else
+ poll_wait(filp, &fh->fh.wait, wait);
+
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return res;
+
if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
(V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) {
- unsigned int res;
-
mutex_lock(&dev->lock);
- res = videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ res |= videobuf_poll_stream(filp, &fh->vb_vidq, wait);
mutex_unlock(&dev->lock);
return res;
}
- return POLLERR;
+ return res | POLLERR;
}
/*
@@ -2479,41 +2184,37 @@ static const struct v4l2_file_operations cx231xx_v4l_fops = {
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
+ .vidioc_querycap = cx231xx_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
.vidioc_cropcap = vidioc_cropcap,
- .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
- .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_enum_input = cx231xx_enum_input,
+ .vidioc_g_input = cx231xx_g_input,
+ .vidioc_s_input = cx231xx_s_input,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_tuner = cx231xx_g_tuner,
+ .vidioc_s_tuner = cx231xx_s_tuner,
+ .vidioc_g_frequency = cx231xx_g_frequency,
+ .vidioc_s_frequency = cx231xx_s_frequency,
+ .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
+ .vidioc_g_register = cx231xx_g_register,
+ .vidioc_s_register = cx231xx_s_register,
#endif
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device cx231xx_vbi_template;
@@ -2523,33 +2224,29 @@ static const struct video_device cx231xx_video_template = {
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
- .current_norm = V4L2_STD_PAL,
};
static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = cx231xx_v4l2_open,
.release = cx231xx_v4l2_close,
- .ioctl = video_ioctl2,
+ .poll = v4l2_ctrl_poll,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
+ .vidioc_querycap = cx231xx_querycap,
.vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
.vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_frequency = cx231xx_g_frequency,
+ .vidioc_s_frequency = cx231xx_s_frequency,
+ .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
+ .vidioc_g_register = cx231xx_g_register,
+ .vidioc_s_register = cx231xx_s_register,
#endif
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device cx231xx_radio_template = {
@@ -2575,10 +2272,17 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
vfd->release = video_device_release;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
video_set_drvdata(vfd, dev);
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
+ }
return vfd;
}
@@ -2590,7 +2294,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
dev->name, CX231XX_VERSION);
/* set default norm */
- /*dev->norm = cx231xx_video_template.current_norm; */
+ dev->norm = V4L2_STD_PAL;
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
dev->interlaced = 0;
@@ -2601,9 +2305,23 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Set the initial input */
video_mux(dev, dev->video_input);
- /* Audio defaults */
- dev->mute = 1;
- dev->volume = 0x1f;
+ call_all(dev, core, s_std, dev->norm);
+
+ v4l2_ctrl_handler_init(&dev->ctrl_handler, 10);
+ v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5);
+
+ if (dev->sd_cx25840) {
+ v4l2_ctrl_add_handler(&dev->ctrl_handler,
+ dev->sd_cx25840->ctrl_handler, NULL);
+ v4l2_ctrl_add_handler(&dev->radio_ctrl_handler,
+ dev->sd_cx25840->ctrl_handler,
+ v4l2_ctrl_radio_filter);
+ }
+
+ if (dev->ctrl_handler.error)
+ return dev->ctrl_handler.error;
+ if (dev->radio_ctrl_handler.error)
+ return dev->radio_ctrl_handler.error;
/* enable vbi capturing */
/* write code here... */
@@ -2615,6 +2333,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
return -ENODEV;
}
+ dev->vdev->ctrl_handler = &dev->ctrl_handler;
/* register v4l2 video video_device */
ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
@@ -2634,6 +2353,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Allocate and fill vbi video_device struct */
dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
+ if (!dev->vbi_dev) {
+ cx231xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+ dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
/* register v4l2 vbi video_device */
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
@@ -2652,6 +2376,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
cx231xx_errdev("cannot allocate video_device.\n");
return -ENODEV;
}
+ dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 3e11462be0d..5ad9fd61d3c 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -33,6 +33,8 @@
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dvb.h>
@@ -69,6 +71,7 @@
#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14
#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15
#define CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2 16
+#define CX231XX_BOARD_OTG102 17
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
@@ -428,27 +431,12 @@ struct cx231xx_audio {
struct cx231xx;
struct cx231xx_fh {
+ struct v4l2_fh fh;
struct cx231xx *dev;
unsigned int stream_on:1; /* Locks streams */
- int radio;
-
- struct videobuf_queue vb_vidq;
-
enum v4l2_buf_type type;
-
-
-/*following is copyed from cx23885.h*/
- u32 resources;
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip *clips;
- unsigned int nclips;
-
- /* video capture */
- struct cx23417_fmt *fmt;
- unsigned int width, height;
+ struct videobuf_queue vb_vidq;
/* vbi capture */
struct videobuf_queue vidq;
@@ -516,14 +504,6 @@ struct cx231xx_tvnorm {
u32 cxoformat;
};
-struct cx231xx_ctrl {
- struct v4l2_queryctrl v;
- u32 off;
- u32 reg;
- u32 mask;
- u32 shift;
-};
-
enum TRANSFER_TYPE {
Raw_Video = 0,
Audio,
@@ -631,6 +611,9 @@ struct cx231xx {
struct v4l2_device v4l2_dev;
struct v4l2_subdev *sd_cx25840;
struct v4l2_subdev *sd_tuner;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl_handler radio_ctrl_handler;
+ struct cx2341x_handler mpeg_ctrl_handler;
struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
atomic_t stream_started; /* stream should be running if true */
@@ -653,8 +636,6 @@ struct cx231xx {
v4l2_std_id norm; /* selected tv norm */
int ctl_freq; /* selected frequency */
unsigned int ctl_ainput; /* selected audio input */
- int mute;
- int volume;
/* frame properties */
int width; /* current frame width */
@@ -736,7 +717,6 @@ struct cx231xx {
u8 USE_ISO;
struct cx231xx_tvnorm encodernorm;
struct cx231xx_tsport ts1, ts2;
- struct cx2341x_mpeg_params mpeg_params;
struct video_device *v4l_device;
atomic_t v4l_reader_count;
u32 freq;
@@ -866,8 +846,6 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
/* Gpio related functions */
int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
u8 len, u8 request, u8 direction);
-int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
-int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value);
int cx231xx_set_gpio_direction(struct cx231xx *dev, int pin_number,
int pin_value);
@@ -955,6 +933,23 @@ int cx231xx_register_extension(struct cx231xx_ops *dev);
void cx231xx_unregister_extension(struct cx231xx_ops *dev);
void cx231xx_init_extension(struct cx231xx *dev);
void cx231xx_close_extension(struct cx231xx *dev);
+int cx231xx_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap);
+int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t);
+int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t);
+int cx231xx_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f);
+int cx231xx_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f);
+int cx231xx_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i);
+int cx231xx_g_input(struct file *file, void *priv, unsigned int *i);
+int cx231xx_s_input(struct file *file, void *priv, unsigned int i);
+int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip);
+int cx231xx_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg);
+int cx231xx_s_register(struct file *file, void *priv,
+ const struct v4l2_dbg_register *reg);
/* Provided by cx231xx-cards.c */
extern void cx231xx_pre_card_setup(struct cx231xx *dev);
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 692224d97d0..a3c8ecf2207 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -13,10 +13,6 @@ config DVB_USB_V2
Say Y if you own a USB DVB device.
-config DVB_USB_CYPRESS_FIRMWARE
- tristate "Cypress firmware helper routines"
- depends on DVB_USB_V2
-
config DVB_USB_AF9015
tristate "Afatech AF9015 DVB-T USB2.0 support"
depends on DVB_USB_V2
@@ -41,6 +37,7 @@ config DVB_USB_AF9035
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_IT913X if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the Afatech AF9035 based DVB USB receiver.
@@ -72,7 +69,7 @@ config DVB_USB_AU6610
config DVB_USB_AZ6007
tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
depends on DVB_USB_V2
- select DVB_USB_CYPRESS_FIRMWARE
+ select CYPRESS_FIRMWARE
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
help
@@ -146,6 +143,7 @@ config DVB_USB_RTL28XXU
select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the Realtek RTL28xxU DVB USB receiver.
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
index b76f58e6c64..2c06714b9ef 100644
--- a/drivers/media/usb/dvb-usb-v2/Makefile
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -1,9 +1,6 @@
dvb_usb_v2-objs := dvb_usb_core.o dvb_usb_urb.o usb_urb.o
obj-$(CONFIG_DVB_USB_V2) += dvb_usb_v2.o
-dvb_usb_cypress_firmware-objs := cypress_firmware.o
-obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o
-
dvb-usb-af9015-objs := af9015.o
obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
@@ -46,4 +43,4 @@ obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
ccflags-y += -I$(srctree)/drivers/media/tuners
-
+ccflags-y += -I$(srctree)/drivers/media/common
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index b86d0f27a39..d556042cf31 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -30,22 +30,22 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
{
-#define BUF_LEN 63
#define REQ_HDR_LEN 8 /* send header size */
#define ACK_HDR_LEN 2 /* rece header size */
struct af9015_state *state = d_to_priv(d);
int ret, wlen, rlen;
- u8 buf[BUF_LEN];
u8 write = 1;
- buf[0] = req->cmd;
- buf[1] = state->seq++;
- buf[2] = req->i2c_addr;
- buf[3] = req->addr >> 8;
- buf[4] = req->addr & 0xff;
- buf[5] = req->mbox;
- buf[6] = req->addr_len;
- buf[7] = req->data_len;
+ mutex_lock(&d->usb_mutex);
+
+ state->buf[0] = req->cmd;
+ state->buf[1] = state->seq++;
+ state->buf[2] = req->i2c_addr;
+ state->buf[3] = req->addr >> 8;
+ state->buf[4] = req->addr & 0xff;
+ state->buf[5] = req->mbox;
+ state->buf[6] = req->addr_len;
+ state->buf[7] = req->data_len;
switch (req->cmd) {
case GET_CONFIG:
@@ -55,14 +55,14 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
break;
case READ_I2C:
write = 0;
- buf[2] |= 0x01; /* set I2C direction */
+ state->buf[2] |= 0x01; /* set I2C direction */
case WRITE_I2C:
- buf[0] = READ_WRITE_I2C;
+ state->buf[0] = READ_WRITE_I2C;
break;
case WRITE_MEMORY:
if (((req->addr & 0xff00) == 0xff00) ||
((req->addr & 0xff00) == 0xae00))
- buf[0] = WRITE_VIRTUAL_MEMORY;
+ state->buf[0] = WRITE_VIRTUAL_MEMORY;
case WRITE_VIRTUAL_MEMORY:
case COPY_FIRMWARE:
case DOWNLOAD_FIRMWARE:
@@ -90,7 +90,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
rlen = ACK_HDR_LEN;
if (write) {
wlen += req->data_len;
- memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
+ memcpy(&state->buf[REQ_HDR_LEN], req->data, req->data_len);
} else {
rlen += req->data_len;
}
@@ -99,22 +99,25 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
rlen = 0;
- ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+ ret = dvb_usbv2_generic_rw_locked(d,
+ state->buf, wlen, state->buf, rlen);
if (ret)
goto error;
/* check status */
- if (rlen && buf[1]) {
+ if (rlen && state->buf[1]) {
dev_err(&d->udev->dev, "%s: command failed=%d\n",
- KBUILD_MODNAME, buf[1]);
+ KBUILD_MODNAME, state->buf[1]);
ret = -EIO;
goto error;
}
/* read request, copy returned data to return buf */
if (!write)
- memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
+ memcpy(req->data, &state->buf[ACK_HDR_LEN], req->data_len);
error:
+ mutex_unlock(&d->usb_mutex);
+
return ret;
}
@@ -1317,6 +1320,43 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
#define af9015_get_rc_config NULL
#endif
+static int af9015_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ char manufacturer[sizeof("ITE Technologies, Inc.")];
+
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ /*
+ * There is two devices having same ID but different chipset. One uses
+ * AF9015 and the other IT9135 chipset. Only difference seen on lsusb
+ * is iManufacturer string.
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 Afatech
+ * iProduct 2 DVB-T 2
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 ITE Technologies, Inc.
+ * iProduct 2 DVB-T TV Stick
+ */
+ if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) &&
+ (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) {
+ if (!strcmp("ITE Technologies, Inc.", manufacturer)) {
+ dev_dbg(&udev->dev, "%s: rejecting device\n", __func__);
+ return -ENODEV;
+ }
+ }
+
+ return dvb_usbv2_probe(intf, id);
+}
+
/* interface 0 is used by DVB-T receiver and
interface 1 is for remote controller (HID) */
static struct dvb_usb_device_properties af9015_props = {
@@ -1425,6 +1465,7 @@ static const struct usb_device_id af9015_id_table[] = {
&af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC,
&af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) },
+ /* XXX: that same ID [0ccd:0099] is used by af9035 driver too */
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
&af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) },
{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T,
@@ -1441,7 +1482,7 @@ MODULE_DEVICE_TABLE(usb, af9015_id_table);
static struct usb_driver af9015_usb_driver = {
.name = KBUILD_MODNAME,
.id_table = af9015_id_table,
- .probe = dvb_usbv2_probe,
+ .probe = af9015_probe,
.disconnect = dvb_usbv2_disconnect,
.suspend = dvb_usbv2_suspend,
.resume = dvb_usbv2_resume,
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h
index 533637dedd2..3a6f3ad1ead 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.h
+++ b/drivers/media/usb/dvb-usb-v2/af9015.h
@@ -115,7 +115,9 @@ enum af9015_ir_mode {
AF9015_IR_MODE_POLLING, /* just guess */
};
+#define BUF_LEN 63
struct af9015_state {
+ u8 buf[BUF_LEN]; /* bulk USB control message */
u8 ir_mode;
u8 rc_repeat;
u32 rc_keycode;
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index f11cc42454f..b638fc1cd57 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -41,79 +41,84 @@ static u16 af9035_checksum(const u8 *buf, size_t len)
static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
{
-#define BUF_LEN 64
#define REQ_HDR_LEN 4 /* send header size */
#define ACK_HDR_LEN 3 /* rece header size */
#define CHECKSUM_LEN 2
#define USB_TIMEOUT 2000
struct state *state = d_to_priv(d);
int ret, wlen, rlen;
- u8 buf[BUF_LEN];
u16 checksum, tmp_checksum;
+ mutex_lock(&d->usb_mutex);
+
/* buffer overflow check */
if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n",
__func__, req->wlen, req->rlen);
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
- buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
- buf[1] = req->mbox;
- buf[2] = req->cmd;
- buf[3] = state->seq++;
- memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen);
+ state->buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
+ state->buf[1] = req->mbox;
+ state->buf[2] = req->cmd;
+ state->buf[3] = state->seq++;
+ memcpy(&state->buf[REQ_HDR_LEN], req->wbuf, req->wlen);
wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN;
rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
/* calc and add checksum */
- checksum = af9035_checksum(buf, buf[0] - 1);
- buf[buf[0] - 1] = (checksum >> 8);
- buf[buf[0] - 0] = (checksum & 0xff);
+ checksum = af9035_checksum(state->buf, state->buf[0] - 1);
+ state->buf[state->buf[0] - 1] = (checksum >> 8);
+ state->buf[state->buf[0] - 0] = (checksum & 0xff);
/* no ack for these packets */
if (req->cmd == CMD_FW_DL)
rlen = 0;
- ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+ ret = dvb_usbv2_generic_rw_locked(d,
+ state->buf, wlen, state->buf, rlen);
if (ret)
- goto err;
+ goto exit;
/* no ack for those packets */
if (req->cmd == CMD_FW_DL)
goto exit;
/* verify checksum */
- checksum = af9035_checksum(buf, rlen - 2);
- tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1];
+ checksum = af9035_checksum(state->buf, rlen - 2);
+ tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1];
if (tmp_checksum != checksum) {
dev_err(&d->udev->dev, "%s: command=%02x checksum mismatch " \
"(%04x != %04x)\n", KBUILD_MODNAME, req->cmd,
tmp_checksum, checksum);
ret = -EIO;
- goto err;
+ goto exit;
}
/* check status */
- if (buf[2]) {
+ if (state->buf[2]) {
+ /* fw returns status 1 when IR code was not received */
+ if (req->cmd == CMD_IR_GET || state->buf[2] == 1) {
+ ret = 1;
+ goto exit;
+ }
+
dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n",
- __func__, req->cmd, buf[2]);
+ __func__, req->cmd, state->buf[2]);
ret = -EIO;
- goto err;
+ goto exit;
}
/* read request, copy returned data to return buf */
if (req->rlen)
- memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
-
+ memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen);
exit:
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
-
+ mutex_unlock(&d->usb_mutex);
+ if (ret < 0)
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -292,12 +297,40 @@ static struct i2c_algorithm af9035_i2c_algo = {
static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
{
+ struct state *state = d_to_priv(d);
int ret;
u8 wbuf[1] = { 1 };
u8 rbuf[4];
struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
sizeof(rbuf), rbuf };
+ ret = af9035_rd_regs(d, 0x1222, rbuf, 3);
+ if (ret < 0)
+ goto err;
+
+ state->chip_version = rbuf[0];
+ state->chip_type = rbuf[2] << 8 | rbuf[1] << 0;
+
+ ret = af9035_rd_reg(d, 0x384f, &state->prechip_version);
+ if (ret < 0)
+ goto err;
+
+ dev_info(&d->udev->dev,
+ "%s: prechip_version=%02x chip_version=%02x chip_type=%04x\n",
+ __func__, state->prechip_version, state->chip_version,
+ state->chip_type);
+
+ if (state->chip_type == 0x9135) {
+ if (state->chip_version == 0x02)
+ *name = AF9035_FIRMWARE_IT9135_V2;
+ else
+ *name = AF9035_FIRMWARE_IT9135_V1;
+ state->eeprom_addr = EEPROM_BASE_IT9135;
+ } else {
+ *name = AF9035_FIRMWARE_AF9035;
+ state->eeprom_addr = EEPROM_BASE_AF9035;
+ }
+
ret = af9035_ctrl_msg(d, &req);
if (ret < 0)
goto err;
@@ -316,66 +349,19 @@ err:
return ret;
}
-static int af9035_download_firmware(struct dvb_usb_device *d,
+static int af9035_download_firmware_old(struct dvb_usb_device *d,
const struct firmware *fw)
{
int ret, i, j, len;
u8 wbuf[1];
- u8 rbuf[4];
struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
- struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
- u8 hdr_core, tmp;
+ u8 hdr_core;
u16 hdr_addr, hdr_data_len, hdr_checksum;
#define MAX_DATA 58
#define HDR_SIZE 7
/*
- * In case of dual tuner configuration we need to do some extra
- * initialization in order to download firmware to slave demod too,
- * which is done by master demod.
- * Master feeds also clock and controls power via GPIO.
- */
- ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
- if (ret < 0)
- goto err;
-
- if (tmp) {
- /* configure gpioh1, reset & power slave demod */
- ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(d, 0x00d8b1, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(d, 0x00d8af, 0x00, 0x01);
- if (ret < 0)
- goto err;
-
- usleep_range(10000, 50000);
-
- ret = af9035_wr_reg_mask(d, 0x00d8af, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- /* tell the slave I2C address */
- ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x00417f, tmp);
- if (ret < 0)
- goto err;
-
- /* enable clock out */
- ret = af9035_wr_reg_mask(d, 0x00d81a, 0x01, 0x01);
- if (ret < 0)
- goto err;
- }
-
- /*
* Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
*
* byte 0: MCS 51 core
@@ -441,28 +427,6 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
if (i)
dev_warn(&d->udev->dev, "%s: bad firmware\n", KBUILD_MODNAME);
- /* firmware loaded, request boot */
- req.cmd = CMD_FW_BOOT;
- ret = af9035_ctrl_msg(d, &req);
- if (ret < 0)
- goto err;
-
- /* ensure firmware starts */
- wbuf[0] = 1;
- ret = af9035_ctrl_msg(d, &req_fw_ver);
- if (ret < 0)
- goto err;
-
- if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
- dev_err(&d->udev->dev, "%s: firmware did not run\n",
- KBUILD_MODNAME);
- ret = -ENODEV;
- goto err;
- }
-
- dev_info(&d->udev->dev, "%s: firmware version=%d.%d.%d.%d",
- KBUILD_MODNAME, rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
-
return 0;
err:
@@ -471,15 +435,11 @@ err:
return ret;
}
-static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
+static int af9035_download_firmware_new(struct dvb_usb_device *d,
const struct firmware *fw)
{
int ret, i, i_prev;
- u8 wbuf[1];
- u8 rbuf[4];
- struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
- struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
#define HDR_SIZE 7
/*
@@ -494,7 +454,6 @@ static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
* 5: addr LSB
* 6: count of data bytes ?
*/
-
for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
if (i == fw->size ||
(fw->data[i + 0] == 0x03 &&
@@ -513,6 +472,86 @@ static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
}
}
+ return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ struct state *state = d_to_priv(d);
+ int ret;
+ u8 wbuf[1];
+ u8 rbuf[4];
+ u8 tmp;
+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ /*
+ * In case of dual tuner configuration we need to do some extra
+ * initialization in order to download firmware to slave demod too,
+ * which is done by master demod.
+ * Master feeds also clock and controls power via GPIO.
+ */
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (tmp) {
+ /* configure gpioh1, reset & power slave demod */
+ ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8b1, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8af, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 50000);
+
+ ret = af9035_wr_reg_mask(d, 0x00d8af, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* tell the slave I2C address */
+ ret = af9035_rd_reg(d,
+ state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR,
+ &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (state->chip_type == 0x9135) {
+ ret = af9035_wr_reg(d, 0x004bfb, tmp);
+ if (ret < 0)
+ goto err;
+ } else {
+ ret = af9035_wr_reg(d, 0x00417f, tmp);
+ if (ret < 0)
+ goto err;
+
+ /* enable clock out */
+ ret = af9035_wr_reg_mask(d, 0x00d81a, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+ }
+
+ if (fw->data[0] == 0x01)
+ ret = af9035_download_firmware_old(d, fw);
+ else
+ ret = af9035_download_firmware_new(d, fw);
+ if (ret < 0)
+ goto err;
+
/* firmware loaded, request boot */
req.cmd = CMD_FW_BOOT;
ret = af9035_ctrl_msg(d, &req);
@@ -546,15 +585,42 @@ err:
static int af9035_read_config(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
- int ret, i, eeprom_shift = 0;
+ int ret, i;
u8 tmp;
- u16 tmp16;
+ u16 tmp16, addr;
/* demod I2C "address" */
state->af9033_config[0].i2c_addr = 0x38;
+ state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
+ state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
+ state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
+ state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
+
+ /* eeprom memory mapped location */
+ if (state->chip_type == 0x9135) {
+ if (state->chip_version == 0x02) {
+ state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
+ state->af9033_config[1].tuner = AF9033_TUNER_IT9135_60;
+ tmp16 = 0x00461d;
+ } else {
+ state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38;
+ state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38;
+ tmp16 = 0x00461b;
+ }
+
+ /* check if eeprom exists */
+ ret = af9035_rd_reg(d, tmp16, &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (tmp == 0x00) {
+ dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__);
+ goto skip_eeprom;
+ }
+ }
/* check if there is dual tuners */
- ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
if (ret < 0)
goto err;
@@ -564,7 +630,9 @@ static int af9035_read_config(struct dvb_usb_device *d)
if (state->dual_mode) {
/* read 2nd demodulator I2C address */
- ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp);
+ ret = af9035_rd_reg(d,
+ state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR,
+ &tmp);
if (ret < 0)
goto err;
@@ -573,17 +641,25 @@ static int af9035_read_config(struct dvb_usb_device *d)
__func__, tmp);
}
+ addr = state->eeprom_addr;
+
for (i = 0; i < state->dual_mode + 1; i++) {
/* tuner */
- ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
+ ret = af9035_rd_reg(d, addr + EEPROM_1_TUNER_ID, &tmp);
if (ret < 0)
goto err;
- state->af9033_config[i].tuner = tmp;
+ if (tmp == 0x00)
+ dev_dbg(&d->udev->dev,
+ "%s: [%d]tuner not set, using default\n",
+ __func__, i);
+ else
+ state->af9033_config[i].tuner = tmp;
+
dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n",
- __func__, i, tmp);
+ __func__, i, state->af9033_config[i].tuner);
- switch (tmp) {
+ switch (state->af9033_config[i].tuner) {
case AF9033_TUNER_TUA9001:
case AF9033_TUNER_FC0011:
case AF9033_TUNER_MXL5007T:
@@ -592,32 +668,46 @@ static int af9035_read_config(struct dvb_usb_device *d)
case AF9033_TUNER_FC0012:
state->af9033_config[i].spec_inv = 1;
break;
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ break;
default:
- dev_warn(&d->udev->dev, "%s: tuner id=%02x not " \
- "supported, please report!",
+ dev_warn(&d->udev->dev,
+ "%s: tuner id=%02x not supported, please report!",
KBUILD_MODNAME, tmp);
}
/* disable dual mode if driver does not support it */
if (i == 1)
- switch (tmp) {
+ switch (state->af9033_config[i].tuner) {
case AF9033_TUNER_FC0012:
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ case AF9033_TUNER_MXL5007T:
break;
default:
state->dual_mode = false;
- dev_info(&d->udev->dev, "%s: driver does not " \
- "support 2nd tuner and will " \
- "disable it", KBUILD_MODNAME);
+ dev_info(&d->udev->dev,
+ "%s: driver does not support 2nd tuner and will disable it",
+ KBUILD_MODNAME);
}
/* tuner IF frequency */
- ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
+ ret = af9035_rd_reg(d, addr + EEPROM_1_IF_L, &tmp);
if (ret < 0)
goto err;
tmp16 = tmp;
- ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
+ ret = af9035_rd_reg(d, addr + EEPROM_1_IF_H, &tmp);
if (ret < 0)
goto err;
@@ -625,9 +715,10 @@ static int af9035_read_config(struct dvb_usb_device *d)
dev_dbg(&d->udev->dev, "%s: [%d]IF=%d\n", __func__, i, tmp16);
- eeprom_shift = 0x10; /* shift for the 2nd tuner params */
+ addr += 0x10; /* shift for the 2nd tuner params */
}
+skip_eeprom:
/* get demod clock */
ret = af9035_rd_reg(d, 0x00d800, &tmp);
if (ret < 0)
@@ -635,34 +726,12 @@ static int af9035_read_config(struct dvb_usb_device *d)
tmp = (tmp >> 0) & 0x0f;
- for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
- state->af9033_config[i].clock = clock_lut[tmp];
-
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int af9035_read_config_it9135(struct dvb_usb_device *d)
-{
- struct state *state = d_to_priv(d);
- int ret, i;
- u8 tmp;
-
- state->dual_mode = false;
-
- /* get demod clock */
- ret = af9035_rd_reg(d, 0x00d800, &tmp);
- if (ret < 0)
- goto err;
-
- tmp = (tmp >> 0) & 0x0f;
-
- for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
- state->af9033_config[i].clock = clock_lut_it9135[tmp];
+ for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) {
+ if (state->chip_type == 0x9135)
+ state->af9033_config[i].clock = clock_lut_it9135[tmp];
+ else
+ state->af9033_config[i].clock = clock_lut_af9035[tmp];
+ }
return 0;
@@ -821,7 +890,12 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
static int af9035_get_adapter_count(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
- return state->dual_mode + 1;
+
+ /* disable 2nd adapter as we don't have PID filters implemented */
+ if (d->udev->speed == USB_SPEED_FULL)
+ return 1;
+ else
+ return state->dual_mode + 1;
}
static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
@@ -829,6 +903,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
struct state *state = adap_to_priv(adap);
struct dvb_usb_device *d = adap_to_d(adap);
int ret;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
if (!state->af9033_config[adap->id].tuner) {
/* unsupported tuner */
@@ -836,20 +911,6 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
goto err;
}
- if (adap->id == 0) {
- state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
- state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
-
- ret = af9035_wr_reg(d, 0x00417f,
- state->af9033_config[1].i2c_addr);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x00d81a, state->dual_mode);
- if (ret < 0)
- goto err;
- }
-
/* attach demodulator */
adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
&d->i2c_adap);
@@ -928,6 +989,8 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
struct dvb_frontend *fe;
struct i2c_msg msg[1];
u8 tuner_addr;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
/*
* XXX: Hack used in that function: we abuse unused I2C address bit [7]
* to carry info about used I2C bus for dual tuner configuration.
@@ -1082,6 +1145,17 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
fe = dvb_attach(fc0012_attach, adap->fe[0], &d->i2c_adap,
&af9035_fc0012_config[adap->id]);
break;
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ /* attach tuner */
+ fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap,
+ state->af9033_config[adap->id].i2c_addr,
+ state->af9033_config[0].tuner);
+ break;
default:
fe = NULL;
}
@@ -1103,8 +1177,8 @@ static int af9035_init(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
int ret, i;
- u16 frame_size = 87 * 188 / 4;
- u8 packet_size = 512 / 4;
+ u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4;
+ u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
struct reg_val_mask tab[] = {
{ 0x80f99d, 0x01, 0x01 },
{ 0x80f9a4, 0x01, 0x01 },
@@ -1149,40 +1223,49 @@ err:
#if IS_ENABLED(CONFIG_RC_CORE)
static int af9035_rc_query(struct dvb_usb_device *d)
{
- unsigned int key;
- unsigned char b[4];
int ret;
- struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
+ u32 key;
+ u8 buf[4];
+ struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, buf };
ret = af9035_ctrl_msg(d, &req);
- if (ret < 0)
+ if (ret == 1)
+ return 0;
+ else if (ret < 0)
goto err;
- if ((b[2] + b[3]) == 0xff) {
- if ((b[0] + b[1]) == 0xff) {
- /* NEC */
- key = b[0] << 8 | b[2];
+ if ((buf[2] + buf[3]) == 0xff) {
+ if ((buf[0] + buf[1]) == 0xff) {
+ /* NEC standard 16bit */
+ key = buf[0] << 8 | buf[2];
} else {
- /* ext. NEC */
- key = b[0] << 16 | b[1] << 8 | b[2];
+ /* NEC extended 24bit */
+ key = buf[0] << 16 | buf[1] << 8 | buf[2];
}
} else {
- key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
+ /* NEC full code 32bit */
+ key = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
+ dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 4, buf);
+
rc_keydown(d->rc_dev, key, 0);
-err:
- /* ignore errors */
return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
}
static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
{
+ struct state *state = d_to_priv(d);
int ret;
u8 tmp;
- ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_MODE, &tmp);
if (ret < 0)
goto err;
@@ -1190,7 +1273,8 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
/* don't activate rc if in HID mode or if not available */
if (tmp == 5) {
- ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_TYPE,
+ &tmp);
if (ret < 0)
goto err;
@@ -1225,6 +1309,109 @@ err:
#define af9035_get_rc_config NULL
#endif
+static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+ struct usb_data_stream_properties *stream)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
+
+ if (d->udev->speed == USB_SPEED_FULL)
+ stream->u.bulk.buffersize = 5 * 188;
+
+ return 0;
+}
+
+/*
+ * FIXME: PID filter is property of demodulator and should be moved to the
+ * correct driver. Also we support only adapter #0 PID filter and will
+ * disable adapter #1 if USB1.1 is used.
+ */
+static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+
+ dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+ ret = af9035_wr_reg_mask(d, 0x80f993, onoff, 0x01);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+ int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+ u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
+
+ dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n",
+ __func__, index, pid, onoff);
+
+ ret = af9035_wr_regs(d, 0x80f996, wbuf, 2);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x80f994, onoff);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x80f995, index);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ char manufacturer[sizeof("Afatech")];
+
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ /*
+ * There is two devices having same ID but different chipset. One uses
+ * AF9015 and the other IT9135 chipset. Only difference seen on lsusb
+ * is iManufacturer string.
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 Afatech
+ * iProduct 2 DVB-T 2
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 ITE Technologies, Inc.
+ * iProduct 2 DVB-T TV Stick
+ */
+ if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) &&
+ (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) {
+ if (!strcmp("Afatech", manufacturer)) {
+ dev_dbg(&udev->dev, "%s: rejecting device\n", __func__);
+ return -ENODEV;
+ }
+ }
+
+ return dvb_usbv2_probe(intf, id);
+}
+
/* interface 0 is used by DVB-T receiver and
interface 1 is for remote controller (HID) */
static const struct dvb_usb_device_properties af9035_props = {
@@ -1237,7 +1424,6 @@ static const struct dvb_usb_device_properties af9035_props = {
.generic_bulk_ctrl_endpoint_response = 0x81,
.identify_state = af9035_identify_state,
- .firmware = AF9035_FIRMWARE_AF9035,
.download_firmware = af9035_download_firmware,
.i2c_algo = &af9035_i2c_algo,
@@ -1246,40 +1432,18 @@ static const struct dvb_usb_device_properties af9035_props = {
.tuner_attach = af9035_tuner_attach,
.init = af9035_init,
.get_rc_config = af9035_get_rc_config,
+ .get_stream_config = af9035_get_stream_config,
.get_adapter_count = af9035_get_adapter_count,
.adapter = {
{
- .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
- }, {
- .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
- },
- },
-};
-
-static const struct dvb_usb_device_properties it9135_props = {
- .driver_name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- .adapter_nr = adapter_nr,
- .size_of_priv = sizeof(struct state),
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .generic_bulk_ctrl_endpoint = 0x02,
- .generic_bulk_ctrl_endpoint_response = 0x81,
-
- .identify_state = af9035_identify_state,
- .firmware = AF9035_FIRMWARE_IT9135,
- .download_firmware = af9035_download_firmware_it9135,
+ .pid_filter_count = 32,
+ .pid_filter_ctrl = af9035_pid_filter_ctrl,
+ .pid_filter = af9035_pid_filter,
- .i2c_algo = &af9035_i2c_algo,
- .read_config = af9035_read_config_it9135,
- .frontend_attach = af9035_frontend_attach,
- .tuner_attach = af9035_tuner_attach,
- .init = af9035_init,
- .get_rc_config = af9035_get_rc_config,
-
- .num_adapters = 1,
- .adapter = {
- {
.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
}, {
.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
@@ -1288,6 +1452,7 @@ static const struct dvb_usb_device_properties it9135_props = {
};
static const struct usb_device_id af9035_id_table[] = {
+ /* AF9035 devices */
{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
&af9035_props, "Afatech AF9035 reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000,
@@ -1312,6 +1477,18 @@ static const struct usb_device_id af9035_id_table[] = {
&af9035_props, "AVerMedia Twinstar (A825)", NULL) },
{ DVB_USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100MINI_PLUS,
&af9035_props, "Asus U3100Mini Plus", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
+ &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) },
+ /* IT9135 devices */
+#if 0
+ { DVB_USB_DEVICE(0x048d, 0x9135,
+ &af9035_props, "IT9135 reference design", NULL) },
+ { DVB_USB_DEVICE(0x048d, 0x9006,
+ &af9035_props, "IT9135 reference design", NULL) },
+#endif
+ /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
+ &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, af9035_id_table);
@@ -1319,7 +1496,7 @@ MODULE_DEVICE_TABLE(usb, af9035_id_table);
static struct usb_driver af9035_usb_driver = {
.name = KBUILD_MODNAME,
.id_table = af9035_id_table,
- .probe = dvb_usbv2_probe,
+ .probe = af9035_probe,
.disconnect = dvb_usbv2_disconnect,
.suspend = dvb_usbv2_suspend,
.resume = dvb_usbv2_resume,
@@ -1334,4 +1511,5 @@ MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Afatech AF9035 driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
-MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index 29f3eec22c2..b5827ca3a01 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -30,6 +30,7 @@
#include "mxl5007t.h"
#include "tda18218.h"
#include "fc2580.h"
+#include "tuner_it913x.h"
struct reg_val {
u32 reg;
@@ -52,12 +53,18 @@ struct usb_req {
};
struct state {
+#define BUF_LEN 64
+ u8 buf[BUF_LEN];
u8 seq; /* packet sequence number */
- bool dual_mode;
+ u8 prechip_version;
+ u8 chip_version;
+ u16 chip_type;
+ u8 dual_mode:1;
+ u16 eeprom_addr;
struct af9033_config af9033_config[2];
};
-u32 clock_lut[] = {
+static const u32 clock_lut_af9035[] = {
20480000, /* FPGA */
16384000, /* 16.38 MHz */
20480000, /* 20.48 MHz */
@@ -72,7 +79,7 @@ u32 clock_lut[] = {
12000000, /* 12.00 MHz */
};
-u32 clock_lut_it9135[] = {
+static const u32 clock_lut_it9135[] = {
12000000, /* 12.00 MHz */
20480000, /* 20.48 MHz */
36000000, /* 36.00 MHz */
@@ -86,19 +93,31 @@ u32 clock_lut_it9135[] = {
};
#define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
-#define AF9035_FIRMWARE_IT9135 "dvb-usb-it9135-01.fw"
+#define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
+#define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
-/* EEPROM locations */
-#define EEPROM_IR_MODE 0x430d
-#define EEPROM_DUAL_MODE 0x4326
-#define EEPROM_2ND_DEMOD_ADDR 0x4327
-#define EEPROM_IR_TYPE 0x4329
-#define EEPROM_1_IFFREQ_L 0x432d
-#define EEPROM_1_IFFREQ_H 0x432e
-#define EEPROM_1_TUNER_ID 0x4331
-#define EEPROM_2_IFFREQ_L 0x433d
-#define EEPROM_2_IFFREQ_H 0x433e
-#define EEPROM_2_TUNER_ID 0x4341
+/*
+ * eeprom is memory mapped as read only. Writing that memory mapped address
+ * will not corrupt eeprom.
+ *
+ * eeprom has value 0x00 single mode and 0x03 for dual mode as far as I have
+ * seen to this day.
+ */
+
+#define EEPROM_BASE_AF9035 0x42fd
+#define EEPROM_BASE_IT9135 0x499c
+#define EEPROM_SHIFT 0x10
+
+#define EEPROM_IR_MODE 0x10
+#define EEPROM_DUAL_MODE 0x29
+#define EEPROM_2ND_DEMOD_ADDR 0x2a
+#define EEPROM_IR_TYPE 0x2c
+#define EEPROM_1_IF_L 0x30
+#define EEPROM_1_IF_H 0x31
+#define EEPROM_1_TUNER_ID 0x34
+#define EEPROM_2_IF_L 0x40
+#define EEPROM_2_IF_H 0x41
+#define EEPROM_2_TUNER_ID 0x44
/* USB commands */
#define CMD_MEM_RD 0x00
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index a20d691d0b6..90cfa35ef6e 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -45,25 +45,24 @@
#include "cxd2820r.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-static DEFINE_MUTEX(anysee_usb_mutex);
-static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
- u8 *rbuf, u8 rlen)
+static int anysee_ctrl_msg(struct dvb_usb_device *d,
+ u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen)
{
struct anysee_state *state = d_to_priv(d);
int act_len, ret, i;
- u8 buf[64];
- memcpy(&buf[0], sbuf, slen);
- buf[60] = state->seq++;
+ mutex_lock(&d->usb_mutex);
- mutex_lock(&anysee_usb_mutex);
+ memcpy(&state->buf[0], sbuf, slen);
+ state->buf[60] = state->seq++;
- dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, buf);
+ dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf);
/* We need receive one message more after dvb_usb_generic_rw due
to weird transaction flow, which is 1 x send + 2 x receive. */
- ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf));
+ ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf),
+ state->buf, sizeof(state->buf));
if (ret)
goto error_unlock;
@@ -82,20 +81,19 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
for (i = 0; i < 3; i++) {
/* receive 2nd answer */
ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
- d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf),
- &act_len, 2000);
-
+ d->props->generic_bulk_ctrl_endpoint),
+ state->buf, sizeof(state->buf), &act_len, 2000);
if (ret) {
- dev_dbg(&d->udev->dev, "%s: recv bulk message " \
- "failed=%d\n", __func__, ret);
+ dev_dbg(&d->udev->dev,
+ "%s: recv bulk message failed=%d\n",
+ __func__, ret);
} else {
dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
- rlen, buf);
-
- if (buf[63] != 0x4f)
- dev_dbg(&d->udev->dev, "%s: cmd failed\n",
- __func__);
+ rlen, state->buf);
+ if (state->buf[63] != 0x4f)
+ dev_dbg(&d->udev->dev,
+ "%s: cmd failed\n", __func__);
break;
}
}
@@ -109,11 +107,10 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
/* read request, copy returned data to return buf */
if (rbuf && rlen)
- memcpy(rbuf, buf, rlen);
+ memcpy(rbuf, state->buf, rlen);
error_unlock:
- mutex_unlock(&anysee_usb_mutex);
-
+ mutex_unlock(&d->usb_mutex);
return ret;
}
@@ -638,7 +635,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
struct anysee_state *state = adap_to_priv(adap);
struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
+ int ret = 0;
u8 tmp;
struct i2c_msg msg[2] = {
{
@@ -884,9 +881,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (!adap->fe[0]) {
/* we have no frontend :-( */
ret = -ENODEV;
- dev_err(&d->udev->dev, "%s: Unsupported Anysee version. " \
- "Please report the " \
- "<linux-media@vger.kernel.org>.\n",
+ dev_err(&d->udev->dev,
+ "%s: Unsupported Anysee version. Please report to <linux-media@vger.kernel.org>.\n",
KBUILD_MODNAME);
}
error:
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h
index c1a4273f14f..8f426d9fc6e 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.h
+++ b/drivers/media/usb/dvb-usb-v2/anysee.h
@@ -52,8 +52,9 @@ enum cmd {
};
struct anysee_state {
- u8 hw; /* PCB ID */
+ u8 buf[64];
u8 seq;
+ u8 hw; /* PCB ID */
u8 fe_id:1; /* frondend ID */
u8 has_ci:1;
u8 ci_attached:1;
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index 70ec80d8be7..44c64ef361b 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -842,7 +842,7 @@ static int az6007_download_firmware(struct dvb_usb_device *d,
{
pr_debug("Loading az6007 firmware\n");
- return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
+ return cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
}
/* DVB USB Driver stuff */
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
deleted file mode 100644
index 211df549f26..00000000000
--- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* cypress_firmware.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file contains functions for downloading the firmware to Cypress FX 1
- * and 2 based devices.
- *
- */
-
-#include "dvb_usb.h"
-#include "cypress_firmware.h"
-
-struct usb_cypress_controller {
- u8 id;
- const char *name; /* name of the usb controller */
- u16 cs_reg; /* needs to be restarted,
- * when the firmware has been downloaded */
-};
-
-static const struct usb_cypress_controller cypress[] = {
- { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 },
- { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 },
- { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 },
-};
-
-/*
- * load a firmware packet to the device
- */
-static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data,
- u8 len)
-{
- dvb_usb_dbg_usb_control_msg(udev,
- 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len);
-
- return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
-}
-
-int usbv2_cypress_load_firmware(struct usb_device *udev,
- const struct firmware *fw, int type)
-{
- struct hexline *hx;
- int ret, pos = 0;
-
- hx = kmalloc(sizeof(struct hexline), GFP_KERNEL);
- if (!hx) {
- dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME);
- return -ENOMEM;
- }
-
- /* stop the CPU */
- hx->data[0] = 1;
- ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1);
- if (ret != 1) {
- dev_err(&udev->dev, "%s: CPU stop failed=%d\n",
- KBUILD_MODNAME, ret);
- ret = -EIO;
- goto err_kfree;
- }
-
- /* write firmware to memory */
- for (;;) {
- ret = dvb_usbv2_get_hexline(fw, hx, &pos);
- if (ret < 0)
- goto err_kfree;
- else if (ret == 0)
- break;
-
- ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
- if (ret < 0) {
- goto err_kfree;
- } else if (ret != hx->len) {
- dev_err(&udev->dev, "%s: error while transferring " \
- "firmware (transferred size=%d, " \
- "block size=%d)\n",
- KBUILD_MODNAME, ret, hx->len);
- ret = -EIO;
- goto err_kfree;
- }
- }
-
- /* start the CPU */
- hx->data[0] = 0;
- ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1);
- if (ret != 1) {
- dev_err(&udev->dev, "%s: CPU start failed=%d\n",
- KBUILD_MODNAME, ret);
- ret = -EIO;
- goto err_kfree;
- }
-
- ret = 0;
-err_kfree:
- kfree(hx);
- return ret;
-}
-EXPORT_SYMBOL(usbv2_cypress_load_firmware);
-
-int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
- int *pos)
-{
- u8 *b = (u8 *) &fw->data[*pos];
- int data_offs = 4;
-
- if (*pos >= fw->size)
- return 0;
-
- memset(hx, 0, sizeof(struct hexline));
- hx->len = b[0];
-
- if ((*pos + hx->len + 4) >= fw->size)
- return -EINVAL;
-
- hx->addr = b[1] | (b[2] << 8);
- hx->type = b[3];
-
- if (hx->type == 0x04) {
- /* b[4] and b[5] are the Extended linear address record data
- * field */
- hx->addr |= (b[4] << 24) | (b[5] << 16);
- }
-
- memcpy(hx->data, &b[data_offs], hx->len);
- hx->chk = b[hx->len + data_offs];
- *pos += hx->len + 5;
-
- return *pos;
-}
-EXPORT_SYMBOL(dvb_usbv2_get_hexline);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Cypress firmware download");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h
deleted file mode 100644
index 80085fd4132..00000000000
--- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* cypress_firmware.h is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file contains functions for downloading the firmware to Cypress FX 1
- * and 2 based devices.
- *
- */
-
-#ifndef CYPRESS_FIRMWARE_H
-#define CYPRESS_FIRMWARE_H
-
-#define CYPRESS_AN2135 0
-#define CYPRESS_AN2235 1
-#define CYPRESS_FX2 2
-
-/* commonly used firmware download types and function */
-struct hexline {
- u8 len;
- u32 addr;
- u8 type;
- u8 data[255];
- u8 chk;
-};
-extern int usbv2_cypress_load_firmware(struct usb_device *,
- const struct firmware *, int);
-extern int dvb_usbv2_get_hexline(const struct firmware *,
- struct hexline *, int *);
-
-#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 3cac8bd0b11..658c6d47fdf 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -329,13 +329,16 @@ struct dvb_usb_adapter {
u8 feed_count;
u8 max_feed_count;
s8 active_fe;
+#define ADAP_INIT 0
+#define ADAP_SLEEP 1
+#define ADAP_STREAMING 2
+ unsigned long state_bits;
/* dvb */
struct dvb_adapter dvb_adap;
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
- struct mutex sync_mutex;
struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP];
int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
@@ -400,5 +403,9 @@ extern int dvb_usbv2_reset_resume(struct usb_interface *);
/* the generic read/write method for device control */
extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16);
extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16);
+/* caller must hold lock when locked versions are called */
+extern int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *,
+ u8 *, u16, u8 *, u16);
+extern int dvb_usbv2_generic_write_locked(struct dvb_usb_device *, u8 *, u16);
#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 08679205591..19f6737d981 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -28,10 +28,11 @@ MODULE_PARM_DESC(disable_rc_polling,
static int dvb_usb_force_pid_filter_usage;
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage,
int, 0444);
-MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \
- "PID filter, if any (default: 0)");
+MODULE_PARM_DESC(force_pid_filter_usage,
+ "force all DVB USB devices to use a PID filter, if any (default: 0)");
-static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name)
+static int dvb_usbv2_download_firmware(struct dvb_usb_device *d,
+ const char *name)
{
int ret;
const struct firmware *fw;
@@ -44,10 +45,9 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam
ret = request_firmware(&fw, name, &d->udev->dev);
if (ret < 0) {
- dev_err(&d->udev->dev, "%s: Did not find the firmware file "\
- "'%s'. Please see linux/Documentation/dvb/ " \
- "for more details on firmware-problems. " \
- "Status %d\n", KBUILD_MODNAME, name, ret);
+ dev_err(&d->udev->dev,
+ "%s: Did not find the firmware file '%s'. Please see linux/Documentation/dvb/ for more details on firmware-problems. Status %d\n",
+ KBUILD_MODNAME, name, ret);
goto err;
}
@@ -181,9 +181,9 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
/* initialize a work queue for handling polling */
INIT_DELAYED_WORK(&d->rc_query_work,
dvb_usb_read_remote_control);
- dev_info(&d->udev->dev, "%s: schedule remote query interval " \
- "to %d msecs\n", KBUILD_MODNAME,
- d->rc.interval);
+ dev_info(&d->udev->dev,
+ "%s: schedule remote query interval to %d msecs\n",
+ KBUILD_MODNAME, d->rc.interval);
schedule_delayed_work(&d->rc_query_work,
msecs_to_jiffies(d->rc.interval));
d->rc_polling_active = true;
@@ -253,128 +253,159 @@ static int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
return usb_urb_exitv2(&adap->stream);
}
-static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed,
- int count)
+static int wait_schedule(void *ptr)
+{
+ schedule();
+
+ return 0;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
- dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \
- "setting pid [%s]: %04x (%04d) at index %d '%s'\n",
+ int ret = 0;
+ struct usb_data_stream_properties stream_props;
+ dev_dbg(&d->udev->dev,
+ "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n",
__func__, adap->id, adap->active_fe, dvbdmxfeed->type,
adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
- dvbdmxfeed->pid, dvbdmxfeed->index,
- (count == 1) ? "on" : "off");
+ dvbdmxfeed->pid, dvbdmxfeed->index);
+
+ /* wait init is done */
+ wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule,
+ TASK_UNINTERRUPTIBLE);
if (adap->active_fe == -1)
return -EINVAL;
- adap->feed_count += count;
-
- /* stop feeding if it is last pid */
- if (adap->feed_count == 0) {
- dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__);
-
- if (d->props->streaming_ctrl) {
- ret = d->props->streaming_ctrl(
- adap->fe[adap->active_fe], 0);
- if (ret < 0) {
- dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
- "failed=%d\n", KBUILD_MODNAME,
- ret);
- usb_urb_killv2(&adap->stream);
- goto err_mutex_unlock;
- }
- }
- usb_urb_killv2(&adap->stream);
- mutex_unlock(&adap->sync_mutex);
- }
+ /* skip feed setup if we are already feeding */
+ if (adap->feed_count++ > 0)
+ goto skip_feed_start;
- /* activate the pid on the device pid filter */
- if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->pid_filtering && adap->props->pid_filter) {
- ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
- dvbdmxfeed->pid, (count == 1) ? 1 : 0);
- if (ret < 0)
- dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ /* set 'streaming' status bit */
+ set_bit(ADAP_STREAMING, &adap->state_bits);
+
+ /* resolve input and output streaming parameters */
+ if (d->props->get_stream_config) {
+ memcpy(&stream_props, &adap->props->stream,
+ sizeof(struct usb_data_stream_properties));
+ ret = d->props->get_stream_config(adap->fe[adap->active_fe],
+ &adap->ts_type, &stream_props);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: get_stream_config() failed=%d\n",
KBUILD_MODNAME, ret);
+ } else {
+ stream_props = adap->props->stream;
}
- /* start feeding if it is first pid */
- if (adap->feed_count == 1 && count == 1) {
- struct usb_data_stream_properties stream_props;
- mutex_lock(&adap->sync_mutex);
- dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__);
+ switch (adap->ts_type) {
+ case DVB_USB_FE_TS_TYPE_204:
+ adap->stream.complete = dvb_usb_data_complete_204;
+ break;
+ case DVB_USB_FE_TS_TYPE_RAW:
+ adap->stream.complete = dvb_usb_data_complete_raw;
+ break;
+ case DVB_USB_FE_TS_TYPE_188:
+ default:
+ adap->stream.complete = dvb_usb_data_complete;
+ break;
+ }
- /* resolve input and output streaming paramters */
- if (d->props->get_stream_config) {
- memcpy(&stream_props, &adap->props->stream,
- sizeof(struct usb_data_stream_properties));
- ret = d->props->get_stream_config(
- adap->fe[adap->active_fe],
- &adap->ts_type, &stream_props);
- if (ret < 0)
- goto err_mutex_unlock;
- } else {
- stream_props = adap->props->stream;
- }
+ /* submit USB streaming packets */
+ usb_urb_submitv2(&adap->stream, &stream_props);
- switch (adap->ts_type) {
- case DVB_USB_FE_TS_TYPE_204:
- adap->stream.complete = dvb_usb_data_complete_204;
- break;
- case DVB_USB_FE_TS_TYPE_RAW:
- adap->stream.complete = dvb_usb_data_complete_raw;
- break;
- case DVB_USB_FE_TS_TYPE_188:
- default:
- adap->stream.complete = dvb_usb_data_complete;
- break;
- }
+ /* enable HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter_ctrl) {
+ ret = adap->props->pid_filter_ctrl(adap, 1);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: pid_filter_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
- usb_urb_submitv2(&adap->stream, &stream_props);
-
- if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->props->caps &
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
- adap->props->pid_filter_ctrl) {
- ret = adap->props->pid_filter_ctrl(adap,
- adap->pid_filtering);
- if (ret < 0) {
- dev_err(&d->udev->dev, "%s: " \
- "pid_filter_ctrl() failed=%d\n",
- KBUILD_MODNAME, ret);
- goto err_mutex_unlock;
- }
- }
+ /* ask device to start streaming */
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 1);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: streaming_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+skip_feed_start:
- if (d->props->streaming_ctrl) {
- ret = d->props->streaming_ctrl(
- adap->fe[adap->active_fe], 1);
- if (ret < 0) {
- dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
- "failed=%d\n", KBUILD_MODNAME,
- ret);
- goto err_mutex_unlock;
- }
- }
+ /* add PID to device HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter) {
+ ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+ dvbdmxfeed->pid, 1);
+ if (ret)
+ dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ KBUILD_MODNAME, ret);
}
- return 0;
-err_mutex_unlock:
- mutex_unlock(&adap->sync_mutex);
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ if (ret)
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
-static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
-}
-
static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+ struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret = 0;
+ dev_dbg(&d->udev->dev,
+ "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n",
+ __func__, adap->id, adap->active_fe, dvbdmxfeed->type,
+ adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+ dvbdmxfeed->pid, dvbdmxfeed->index);
+
+ if (adap->active_fe == -1)
+ return -EINVAL;
+
+ /* remove PID from device HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter) {
+ ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+ dvbdmxfeed->pid, 0);
+ if (ret)
+ dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+
+ /* we cannot stop streaming until last PID is removed */
+ if (--adap->feed_count > 0)
+ goto skip_feed_stop;
+
+ /* ask device to stop streaming */
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 0);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: streaming_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+
+ /* disable HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter_ctrl) {
+ ret = adap->props->pid_filter_ctrl(adap, 0);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: pid_filter_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+
+ /* kill USB streaming packets */
+ usb_urb_killv2(&adap->stream);
+
+ /* clear 'streaming' status bit */
+ clear_bit(ADAP_STREAMING, &adap->state_bits);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&adap->state_bits, ADAP_STREAMING);
+skip_feed_stop:
+
+ if (ret)
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
}
static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
@@ -435,8 +466,6 @@ static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
goto err_dvb_net_init;
}
- mutex_init(&adap->sync_mutex);
-
return 0;
err_dvb_net_init:
dvb_dmxdev_release(&adap->dmxdev);
@@ -500,7 +529,7 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe)
if (!adap->suspend_resume_active) {
adap->active_fe = fe->id;
- mutex_lock(&adap->sync_mutex);
+ set_bit(ADAP_INIT, &adap->state_bits);
}
ret = dvb_usbv2_device_power_ctrl(d, 1);
@@ -519,8 +548,11 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe)
goto err;
}
err:
- if (!adap->suspend_resume_active)
- mutex_unlock(&adap->sync_mutex);
+ if (!adap->suspend_resume_active) {
+ clear_bit(ADAP_INIT, &adap->state_bits);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&adap->state_bits, ADAP_INIT);
+ }
dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
return ret;
@@ -534,8 +566,11 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
fe->id);
- if (!adap->suspend_resume_active)
- mutex_lock(&adap->sync_mutex);
+ if (!adap->suspend_resume_active) {
+ set_bit(ADAP_SLEEP, &adap->state_bits);
+ wait_on_bit(&adap->state_bits, ADAP_STREAMING, wait_schedule,
+ TASK_UNINTERRUPTIBLE);
+ }
if (adap->fe_sleep[fe->id]) {
ret = adap->fe_sleep[fe->id](fe);
@@ -555,7 +590,9 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
err:
if (!adap->suspend_resume_active) {
adap->active_fe = -1;
- mutex_unlock(&adap->sync_mutex);
+ clear_bit(ADAP_SLEEP, &adap->state_bits);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&adap->state_bits, ADAP_SLEEP);
}
dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
@@ -574,8 +611,9 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
if (d->props->frontend_attach) {
ret = d->props->frontend_attach(adap);
if (ret < 0) {
- dev_dbg(&d->udev->dev, "%s: frontend_attach() " \
- "failed=%d\n", __func__, ret);
+ dev_dbg(&d->udev->dev,
+ "%s: frontend_attach() failed=%d\n",
+ __func__, ret);
goto err_dvb_frontend_detach;
}
} else {
@@ -595,8 +633,9 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
if (ret < 0) {
- dev_err(&d->udev->dev, "%s: frontend%d registration " \
- "failed\n", KBUILD_MODNAME, i);
+ dev_err(&d->udev->dev,
+ "%s: frontend%d registration failed\n",
+ KBUILD_MODNAME, i);
goto err_dvb_unregister_frontend;
}
@@ -670,33 +709,33 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d)
/* speed - when running at FULL speed we need a HW PID filter */
if (d->udev->speed == USB_SPEED_FULL &&
!(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
- dev_err(&d->udev->dev, "%s: this USB2.0 device " \
- "cannot be run on a USB1.1 port (it " \
- "lacks a hardware PID filter)\n",
+ dev_err(&d->udev->dev,
+ "%s: this USB2.0 device cannot be run on a USB1.1 port (it lacks a hardware PID filter)\n",
KBUILD_MODNAME);
ret = -ENODEV;
goto err;
} else if ((d->udev->speed == USB_SPEED_FULL &&
adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
(adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
- dev_info(&d->udev->dev, "%s: will use the device's " \
- "hardware PID filter " \
- "(table count: %d)\n", KBUILD_MODNAME,
+ dev_info(&d->udev->dev,
+ "%s: will use the device's hardware PID filter (table count: %d)\n",
+ KBUILD_MODNAME,
adap->props->pid_filter_count);
adap->pid_filtering = 1;
adap->max_feed_count = adap->props->pid_filter_count;
} else {
- dev_info(&d->udev->dev, "%s: will pass the complete " \
- "MPEG2 transport stream to the " \
- "software demuxer\n", KBUILD_MODNAME);
+ dev_info(&d->udev->dev,
+ "%s: will pass the complete MPEG2 transport stream to the software demuxer\n",
+ KBUILD_MODNAME);
adap->pid_filtering = 0;
adap->max_feed_count = 255;
}
if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage &&
adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
- dev_info(&d->udev->dev, "%s: PID filter enabled by " \
- "module option\n", KBUILD_MODNAME);
+ dev_info(&d->udev->dev,
+ "%s: PID filter enabled by module option\n",
+ KBUILD_MODNAME);
adap->pid_filtering = 1;
adap->max_feed_count = adap->props->pid_filter_count;
}
@@ -825,8 +864,9 @@ static void dvb_usbv2_init_work(struct work_struct *work)
if (ret == 0) {
;
} else if (ret == COLD) {
- dev_info(&d->udev->dev, "%s: found a '%s' in cold " \
- "state\n", KBUILD_MODNAME, d->name);
+ dev_info(&d->udev->dev,
+ "%s: found a '%s' in cold state\n",
+ KBUILD_MODNAME, d->name);
if (!name)
name = d->props->firmware;
@@ -868,8 +908,9 @@ static void dvb_usbv2_init_work(struct work_struct *work)
if (ret < 0)
goto err_usb_driver_release_interface;
- dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \
- "connected\n", KBUILD_MODNAME, d->name);
+ dev_info(&d->udev->dev,
+ "%s: '%s' successfully initialized and connected\n",
+ KBUILD_MODNAME, d->name);
return;
err_usb_driver_release_interface:
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
index 5716662b483..33ff97e708e 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -21,8 +21,8 @@
#include "dvb_usb_common.h"
-int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
- u16 rlen)
+static int dvb_usb_v2_generic_io(struct dvb_usb_device *d,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
int ret, actual_length;
@@ -32,8 +32,6 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
return -EINVAL;
}
- mutex_lock(&d->usb_mutex);
-
dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf);
ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
@@ -56,20 +54,51 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
d->props->generic_bulk_ctrl_endpoint_response),
rbuf, rlen, &actual_length, 2000);
if (ret)
- dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \
- "failed=%d\n", KBUILD_MODNAME, ret);
+ dev_err(&d->udev->dev,
+ "%s: 2nd usb_bulk_msg() failed=%d\n",
+ KBUILD_MODNAME, ret);
dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
actual_length, rbuf);
}
+ return ret;
+}
+
+int dvb_usbv2_generic_rw(struct dvb_usb_device *d,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ int ret;
+
+ mutex_lock(&d->usb_mutex);
+ ret = dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen);
mutex_unlock(&d->usb_mutex);
+
return ret;
}
EXPORT_SYMBOL(dvb_usbv2_generic_rw);
int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
{
- return dvb_usbv2_generic_rw(d, buf, len, NULL, 0);
+ int ret;
+
+ mutex_lock(&d->usb_mutex);
+ ret = dvb_usb_v2_generic_io(d, buf, len, NULL, 0);
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
}
EXPORT_SYMBOL(dvb_usbv2_generic_write);
+
+int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *d,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ return dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_rw_locked);
+
+int dvb_usbv2_generic_write_locked(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+ return dvb_usb_v2_generic_io(d, buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_write_locked);
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
index 833847995c6..e48cdeb9df4 100644
--- a/drivers/media/usb/dvb-usb-v2/it913x.c
+++ b/drivers/media/usb/dvb-usb-v2/it913x.c
@@ -218,6 +218,7 @@ static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
deb_info(1, "PID_C (%02x)", onoff);
+ st->pid_filter_onoff = adap->pid_filtering;
ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff);
mutex_unlock(&d->i2c_mutex);
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index f30c58cecbb..b3fd0ffa3c3 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -1241,10 +1241,13 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
struct usb_data_stream_properties *stream)
{
struct dvb_usb_adapter *adap = fe_to_adap(fe);
- struct dvb_usb_device *d = adap_to_d(adap);
+ struct dvb_usb_device *d;
if (adap == NULL)
return 0;
+
+ d = adap_to_d(adap);
+
/* Turn PID filter on the fly by module option */
if (pid_filter == 2) {
adap->pid_filtering = 1;
@@ -1299,8 +1302,7 @@ static void lme2510_exit(struct dvb_usb_device *d)
if (d != NULL) {
usb_buffer = lme2510_exit_int(d);
- if (usb_buffer != NULL)
- kfree(usb_buffer);
+ kfree(usb_buffer);
}
}
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
index 432706ae527..3f3f8bfd190 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
@@ -21,6 +21,7 @@
#ifndef __MXL111SF_DEMOD_H__
#define __MXL111SF_DEMOD_H__
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
#include "mxl111sf.h"
@@ -31,8 +32,7 @@ struct mxl111sf_demod_config {
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
};
-#if defined(CONFIG_DVB_USB_MXL111SF) || \
- (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
extern
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
struct mxl111sf_demod_config *cfg);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
index ff333960b18..90f583e5d6a 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
@@ -21,8 +21,8 @@
#ifndef __MXL111SF_TUNER_H__
#define __MXL111SF_TUNER_H__
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
-
#include "mxl111sf.h"
enum mxl_if_freq {
@@ -60,8 +60,7 @@ struct mxl111sf_tuner_config {
/* ------------------------------------------------------------------------ */
-#if defined(CONFIG_DVB_USB_MXL111SF) || \
- (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
extern
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
struct mxl111sf_state *mxl_state,
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index d98387a3c95..22015fe1a0f 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -33,6 +33,7 @@
#include "e4000.h"
#include "fc2580.h"
#include "tua9001.h"
+#include "r820t.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -375,6 +376,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
+ struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 5, buf};
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -479,6 +481,14 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
goto found;
}
+ /* check R820T by reading tuner stats at I2C addr 0x1a */
+ ret = rtl28xxu_ctrl_msg(d, &req_r820t);
+ if (ret == 0) {
+ priv->tuner = TUNER_RTL2832_R820T;
+ priv->tuner_name = "R820T";
+ goto found;
+ }
+
found:
dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
@@ -589,6 +599,12 @@ static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
.tuner = TUNER_RTL2832_E4000,
};
+static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
+ .i2c_addr = 0x10,
+ .xtal = 28800000,
+ .tuner = TUNER_RTL2832_R820T,
+};
+
static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
int cmd, int arg)
{
@@ -728,6 +744,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
case TUNER_RTL2832_E4000:
rtl2832_config = &rtl28xxu_rtl2832_e4000_config;
break;
+ case TUNER_RTL2832_R820T:
+ rtl2832_config = &rtl28xxu_rtl2832_r820t_config;
+ break;
default:
dev_err(&d->udev->dev, "%s: unknown tuner=%s\n",
KBUILD_MODNAME, priv->tuner_name);
@@ -840,6 +859,13 @@ static const struct fc0012_config rtl2832u_fc0012_config = {
.xtal_freq = FC_XTAL_28_8_MHZ,
};
+static const struct r820t_config rtl2832u_r820t_config = {
+ .i2c_addr = 0x1a,
+ .xtal = 28800000,
+ .max_i2c_msg_len = 2,
+ .rafael_chip = CHIP_R820T,
+};
+
static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
@@ -889,6 +915,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap,
&rtl2832u_tua9001_config);
break;
+ case TUNER_RTL2832_R820T:
+ fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
+ &rtl2832u_r820t_config);
+
+ /* Use tuner to get the signal strength */
+ adap->fe[0]->ops.read_signal_strength =
+ adap->fe[0]->ops.tuner_ops.get_rf_strength;
+ break;
default:
fe = NULL;
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
@@ -1372,6 +1406,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "Digivox Micro Hd", NULL) },
{ DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620,
&rtl2832u_props, "Compro VideoMate U620F", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
+ &rtl2832u_props, "MaxMedia HU394-T", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 2f3af2d3b6c..533a3312728 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -82,6 +82,7 @@ enum rtl28xxu_tuner {
TUNER_RTL2832_E4000,
TUNER_RTL2832_TDA18272,
TUNER_RTL2832_FC0013,
+ TUNER_RTL2832_R820T,
};
struct rtl28xxu_req {
diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c
index 7346f85f3f2..ca8f3c2b108 100644
--- a/drivers/media/usb/dvb-usb-v2/usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c
@@ -22,8 +22,8 @@ static void usb_urb_complete(struct urb *urb)
int i;
u8 *b;
- dev_dbg_ratelimited(&stream->udev->dev, "%s: %s urb completed " \
- "status=%d length=%d/%d pack_num=%d errors=%d\n",
+ dev_dbg_ratelimited(&stream->udev->dev,
+ "%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n",
__func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
urb->status, urb->actual_length,
urb->transfer_buffer_length,
@@ -49,8 +49,8 @@ static void usb_urb_complete(struct urb *urb)
case PIPE_ISOCHRONOUS:
for (i = 0; i < urb->number_of_packets; i++) {
if (urb->iso_frame_desc[i].status != 0)
- dev_dbg(&stream->udev->dev, "%s: iso frame " \
- "descriptor has an error=%d\n",
+ dev_dbg(&stream->udev->dev,
+ "%s: iso frame descriptor has an error=%d\n",
__func__,
urb->iso_frame_desc[i].status);
else if (urb->iso_frame_desc[i].actual_length > 0)
@@ -67,8 +67,9 @@ static void usb_urb_complete(struct urb *urb)
stream->complete(stream, b, urb->actual_length);
break;
default:
- dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \
- "completition handler\n", KBUILD_MODNAME);
+ dev_err(&stream->udev->dev,
+ "%s: unknown endpoint type in completition handler\n",
+ KBUILD_MODNAME);
return;
}
usb_submit_urb(urb, GFP_ATOMIC);
@@ -101,8 +102,8 @@ int usb_urb_submitv2(struct usb_data_stream *stream,
dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
if (ret) {
- dev_err(&stream->udev->dev, "%s: could not submit " \
- "urb no. %d - get them all back\n",
+ dev_err(&stream->udev->dev,
+ "%s: could not submit urb no. %d - get them all back\n",
KBUILD_MODNAME, i);
usb_urb_killv2(stream);
return ret;
@@ -229,8 +230,9 @@ static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
stream->buf_num = 0;
stream->buf_size = size;
- dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \
- "streaming\n", __func__, num * size);
+ dev_dbg(&stream->udev->dev,
+ "%s: all in all I will use %lu bytes for streaming\n",
+ __func__, num * size);
for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
stream->buf_list[stream->buf_num] = usb_alloc_coherent(
@@ -274,8 +276,8 @@ int usb_urb_reconfig(struct usb_data_stream *stream,
}
if (stream->buf_num < props->count || stream->buf_size < buf_size) {
- dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \
- "allocated buffers are too small\n",
+ dev_err(&stream->udev->dev,
+ "%s: cannot reconfigure as allocated buffers are too small\n",
KBUILD_MODNAME);
return -EINVAL;
}
@@ -321,8 +323,9 @@ int usb_urb_initv2(struct usb_data_stream *stream,
memcpy(&stream->props, props, sizeof(*props));
if (!stream->complete) {
- dev_err(&stream->udev->dev, "%s: there is no data callback - " \
- "this doesn't make sense\n", KBUILD_MODNAME);
+ dev_err(&stream->udev->dev,
+ "%s: there is no data callback - this doesn't make sense\n",
+ KBUILD_MODNAME);
return -EINVAL;
}
@@ -343,8 +346,9 @@ int usb_urb_initv2(struct usb_data_stream *stream,
return usb_urb_alloc_isoc_urbs(stream);
default:
- dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \
- "transfer\n", KBUILD_MODNAME);
+ dev_err(&stream->udev->dev,
+ "%s: unknown urb-type for data transfer\n",
+ KBUILD_MODNAME);
return -EINVAL;
}
}
diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
index 1efc028a76c..c890fe46acd 100644
--- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c
+++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
@@ -300,8 +300,7 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
static void cinergyt2_fe_release(struct dvb_frontend *fe)
{
struct cinergyt2_fe_state *state = fe->demodulator_priv;
- if (state != NULL)
- kfree(state);
+ kfree(state);
}
static struct dvb_frontend_ops cinergyt2_fe_ops;
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 11798426fa8..f08136052f9 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -1431,13 +1431,22 @@ static int dib8090_get_adc_power(struct dvb_frontend *fe)
return dib8000_get_adc_power(fe, 1);
}
+static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart)
+{
+ deb_info("AGC control callback: %i\n", restart);
+ dib0090_dcc_freq(fe, restart);
+
+ if (restart == 0) /* before AGC startup */
+ dib0090_set_dc_servo(fe, 1);
+}
+
static struct dib8000_config dib809x_dib8000_config[2] = {
{
.output_mpeg2_in_188_bytes = 1,
.agc_config_count = 2,
.agc = dib8090_agc_config,
- .agc_control = dib0090_dcc_freq,
+ .agc_control = dib8090_agc_control,
.pll = &dib8090_pll_config_12mhz,
.tuner_is_baseband = 1,
@@ -1456,7 +1465,7 @@ static struct dib8000_config dib809x_dib8000_config[2] = {
.agc_config_count = 2,
.agc = dib8090_agc_config,
- .agc_control = dib0090_dcc_freq,
+ .agc_control = dib8090_agc_control,
.pll = &dib8090_pll_config_12mhz,
.tuner_is_baseband = 1,
@@ -1504,28 +1513,89 @@ static struct dib0090_config dib809x_dib0090_config = {
.fref_clock_ratio = 6,
};
+static u8 dib8090_compute_pll_parameters(struct dvb_frontend *fe)
+{
+ u8 optimal_pll_ratio = 20;
+ u32 freq_adc, ratio, rest, max = 0;
+ u8 pll_ratio;
+
+ for (pll_ratio = 17; pll_ratio <= 20; pll_ratio++) {
+ freq_adc = 12 * pll_ratio * (1 << 8) / 16;
+ ratio = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) / freq_adc;
+ rest = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) - ratio * freq_adc;
+
+ if (rest > freq_adc / 2)
+ rest = freq_adc - rest;
+ deb_info("PLL ratio=%i rest=%i\n", pll_ratio, rest);
+ if ((rest > max) && (rest > 717)) {
+ optimal_pll_ratio = pll_ratio;
+ max = rest;
+ }
+ }
+ deb_info("optimal PLL ratio=%i\n", optimal_pll_ratio);
+
+ return optimal_pll_ratio;
+}
+
static int dib8096_set_param_override(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
- u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
- u16 target;
+ u8 pll_ratio, band = BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
+ u16 target, ltgain, rf_gain_limit;
+ u32 timf;
int ret = 0;
enum frontend_tune_state tune_state = CT_SHUTDOWN;
- u16 ltgain, rf_gain_limit;
+
+ switch (band) {
+ default:
+ deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
+ case BAND_VHF:
+ dib8000_set_gpio(fe, 3, 0, 1);
+ break;
+ case BAND_UHF:
+ dib8000_set_gpio(fe, 3, 0, 0);
+ break;
+ }
ret = state->set_param_save(fe);
if (ret < 0)
return ret;
- target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
- dib8000_set_wbd_ref(fe, target);
+ if (fe->dtv_property_cache.bandwidth_hz != 6000000) {
+ deb_info("only 6MHz bandwidth is supported\n");
+ return -EINVAL;
+ }
+
+ /** Update PLL if needed ratio **/
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+
+ /** Get optimize PLL ratio to remove spurious **/
+ pll_ratio = dib8090_compute_pll_parameters(fe);
+ if (pll_ratio == 17)
+ timf = 21387946;
+ else if (pll_ratio == 18)
+ timf = 20199727;
+ else if (pll_ratio == 19)
+ timf = 19136583;
+ else
+ timf = 18179756;
+
+ /** Update ratio **/
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio);
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, timf);
+
+ if (band != BAND_CBAND) {
+ /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */
+ target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
+ dib8000_set_wbd_ref(fe, target);
+ }
if (band == BAND_CBAND) {
deb_info("tuning in CBAND - soft-AGC startup\n");
dib0090_set_tune_state(fe, CT_AGC_START);
+
do {
ret = dib0090_gain_control(fe);
msleep(ret);
@@ -1534,14 +1604,17 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
dib8000_set_gpio(fe, 6, 0, 1);
else if (tune_state == CT_AGC_STEP_1) {
dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
- if (rf_gain_limit == 0)
+ if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */
dib8000_set_gpio(fe, 6, 0, 0);
}
} while (tune_state < CT_AGC_STOP);
+
+ deb_info("switching to PWM AGC\n");
dib0090_pwm_gain_reset(fe);
dib8000_pwm_agc_reset(fe);
dib8000_set_tune_state(fe, CT_DEMOD_START);
} else {
+ /* for everything else than CBAND we are using standard AGC */
deb_info("not tuning in CBAND - standard AGC startup\n");
dib0090_pwm_gain_reset(fe);
}
@@ -1814,21 +1887,92 @@ struct dibx090p_adc {
u32 pll_prediv; /* New loopdiv */
};
-struct dibx090p_adc dib8090p_adc_tab[] = {
- { 50000, 17043521, 16, 3}, /* 64 MHz */
- {878000, 20199729, 9, 1}, /* 60 MHz */
- {0xffffffff, 0, 0, 0}, /* 60 MHz */
+struct dibx090p_best_adc {
+ u32 timf;
+ u32 pll_loopdiv;
+ u32 pll_prediv;
};
+static int dib8096p_get_best_sampling(struct dvb_frontend *fe, struct dibx090p_best_adc *adc)
+{
+ u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
+ u16 xtal = 12000;
+ u16 fcp_min = 1900; /* PLL, Minimum Frequency of phase comparator (KHz) */
+ u16 fcp_max = 20000; /* PLL, Maximum Frequency of phase comparator (KHz) */
+ u32 fmem_max = 140000; /* 140MHz max SDRAM freq */
+ u32 fdem_min = 66000;
+ u32 fcp = 0, fs = 0, fdem = 0, fmem = 0;
+ u32 harmonic_id = 0;
+
+ adc->timf = 0;
+ adc->pll_loopdiv = loopdiv;
+ adc->pll_prediv = prediv;
+
+ deb_info("bandwidth = %d", fe->dtv_property_cache.bandwidth_hz);
+
+ /* Find Min and Max prediv */
+ while ((xtal / max_prediv) >= fcp_min)
+ max_prediv++;
+
+ max_prediv--;
+ min_prediv = max_prediv;
+ while ((xtal / min_prediv) <= fcp_max) {
+ min_prediv--;
+ if (min_prediv == 1)
+ break;
+ }
+ deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
+
+ min_prediv = 1;
+
+ for (prediv = min_prediv; prediv < max_prediv; prediv++) {
+ fcp = xtal / prediv;
+ if (fcp > fcp_min && fcp < fcp_max) {
+ for (loopdiv = 1; loopdiv < 64; loopdiv++) {
+ fmem = ((xtal/prediv) * loopdiv);
+ fdem = fmem / 2;
+ fs = fdem / 4;
+
+ /* test min/max system restrictions */
+ if ((fdem >= fdem_min) && (fmem <= fmem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz / 1000)) {
+ spur = 0;
+ /* test fs harmonics positions */
+ for (harmonic_id = (fe->dtv_property_cache.frequency / (1000 * fs)); harmonic_id <= ((fe->dtv_property_cache.frequency / (1000 * fs)) + 1); harmonic_id++) {
+ if (((fs * harmonic_id) >= (fe->dtv_property_cache.frequency / 1000 - (fe->dtv_property_cache.bandwidth_hz / 2000))) && ((fs * harmonic_id) <= (fe->dtv_property_cache.frequency / 1000 + (fe->dtv_property_cache.bandwidth_hz / 2000)))) {
+ spur = 1;
+ break;
+ }
+ }
+
+ if (!spur) {
+ adc->pll_loopdiv = loopdiv;
+ adc->pll_prediv = prediv;
+ adc->timf = (4260880253U / fdem) * (1 << 8);
+ adc->timf += ((4260880253U % fdem) << 8) / fdem;
+
+ deb_info("RF %6d; BW %6d; Xtal %6d; Fmem %6d; Fdem %6d; Fs %6d; Prediv %2d; Loopdiv %2d; Timf %8d;", fe->dtv_property_cache.frequency, fe->dtv_property_cache.bandwidth_hz, xtal, fmem, fdem, fs, prediv, loopdiv, adc->timf);
+ break;
+ }
+ }
+ }
+ }
+ if (!spur)
+ break;
+ }
+
+ if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
+ return -EINVAL;
+ return 0;
+}
+
static int dib8096p_agc_startup(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
struct dibx000_bandwidth_config pll;
+ struct dibx090p_best_adc adc;
u16 target;
- int better_sampling_freq = 0, ret;
- struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
+ int ret;
ret = state->set_param_save(fe);
if (ret < 0)
@@ -1841,23 +1985,27 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe)
target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
dib8000_set_wbd_ref(fe, target);
+ if (dib8096p_get_best_sampling(fe, &adc) == 0) {
+ pll.pll_ratio = adc.pll_loopdiv;
+ pll.pll_prediv = adc.pll_prediv;
- while (p->frequency / 1000 > adc_table->freq) {
- better_sampling_freq = 1;
- adc_table++;
- }
-
- if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
- pll.pll_ratio = adc_table->pll_loopdiv;
- pll.pll_prediv = adc_table->pll_prediv;
- dib8000_update_pll(fe, &pll);
- dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
+ dib0700_set_i2c_speed(adap->dev, 200);
+ dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+ dib0700_set_i2c_speed(adap->dev, 1000);
}
return 0;
}
static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_state *st = adap->dev->priv;
+ u32 fw_version;
+
+ dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+ if (fw_version >= 0x10200)
+ st->fw_use_new_i2c_api = 1;
+
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(20);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
@@ -2242,13 +2390,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
}
/* NIM7090 */
-struct dib7090p_best_adc {
- u32 timf;
- u32 pll_loopdiv;
- u32 pll_prediv;
-};
-
-static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
+static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dibx090p_best_adc *adc)
{
u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
@@ -2327,7 +2469,7 @@ static int dib7090_agc_startup(struct dvb_frontend *fe)
struct dib0700_adapter_state *state = adap->priv;
struct dibx000_bandwidth_config pll;
u16 target;
- struct dib7090p_best_adc adc;
+ struct dibx090p_best_adc adc;
int ret;
ret = state->set_param_save(fe);
@@ -2357,36 +2499,16 @@ static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
return 0;
}
-static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global)
+static int tfe7790p_update_lna(struct dvb_frontend *fe, u16 agc_global)
{
- u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1;
- s16 wbd_delta;
+ deb_info("update LNA: agc global=%i", agc_global);
- if ((fe->dtv_property_cache.frequency) < 400000000)
- threshold_agc1 = 25000;
- else
- threshold_agc1 = 30000;
-
- wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2;
- wbd_offset = dib0090_get_wbd_offset(fe);
- dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd);
- wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ;
-
- deb_info("update lna, agc_global=%d agc1=%d agc2=%d",
- agc_global, agc1, agc2);
- deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d",
- wbd, wbd_target, wbd_offset, wbd_delta);
-
- if ((agc1 < threshold_agc1) && (wbd_delta > 0)) {
- dib0090_set_switch(fe, 1, 1, 1);
- dib0090_set_vga(fe, 0);
- dib0090_update_rframp_7090(fe, 0);
- dib0090_update_tuning_table_7090(fe, 0);
+ if (agc_global < 25000) {
+ dib7000p_set_gpio(fe, 8, 0, 0);
+ dib7000p_set_agc1_min(fe, 0);
} else {
- dib0090_set_vga(fe, 1);
- dib0090_update_rframp_7090(fe, 1);
- dib0090_update_tuning_table_7090(fe, 1);
- dib0090_set_switch(fe, 0, 0, 0);
+ dib7000p_set_gpio(fe, 8, 0, 1);
+ dib7000p_set_agc1_min(fe, 32768);
}
return 0;
@@ -2400,15 +2522,6 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = {
{ 0xFFFF, 0, 0, 0, 0, 0},
};
-static struct dib0090_wbd_slope dib7090e_wbd_table[] = {
- { 380, 81, 850, 64, 540, 4},
- { 700, 51, 866, 21, 320, 4},
- { 860, 48, 666, 18, 330, 6},
- {1700, 0, 250, 0, 100, 6},
- {2600, 0, 250, 0, 100, 6},
- { 0xFFFF, 0, 0, 0, 0, 0},
-};
-
static struct dibx000_agc_config dib7090_agc_config[2] = {
{
.band_caps = BAND_UHF,
@@ -2428,7 +2541,7 @@ static struct dibx000_agc_config dib7090_agc_config[2] = {
.wbd_alpha = 5,
.agc1_max = 65535,
- .agc1_min = 0,
+ .agc1_min = 32768,
.agc2_max = 65535,
.agc2_min = 0,
@@ -2505,7 +2618,7 @@ static struct dib7000p_config nim7090_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7790p_update_lna, /* GPIO used is the same as TFE7790 */
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2529,12 +2642,26 @@ static struct dib7000p_config nim7090_dib7000p_config = {
.enMpegOutput = 1,
};
+static int tfe7090p_pvr_update_lna(struct dvb_frontend *fe, u16 agc_global)
+{
+ deb_info("TFE7090P-PVR update LNA: agc global=%i", agc_global);
+ if (agc_global < 25000) {
+ dib7000p_set_gpio(fe, 5, 0, 0);
+ dib7000p_set_agc1_min(fe, 0);
+ } else {
+ dib7000p_set_gpio(fe, 5, 0, 1);
+ dib7000p_set_agc1_min(fe, 32768);
+ }
+
+ return 0;
+}
+
static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
{
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7090p_pvr_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2561,7 +2688,7 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7090p_pvr_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2587,34 +2714,6 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
}
};
-static struct dib7000p_config tfe7090e_dib7000p_config = {
- .output_mpeg2_in_188_bytes = 1,
- .hostbus_diversity = 1,
- .tuner_is_baseband = 1,
- .update_lna = dib7090e_update_lna,
-
- .agc_config_count = 2,
- .agc = dib7090_agc_config,
-
- .bw = &dib7090_clock_config_12_mhz,
-
- .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
- .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
- .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
- .pwm_freq_div = 0,
-
- .agc_control = dib7090_agc_restart,
-
- .spur_protect = 0,
- .disable_sample_and_hold = 0,
- .enable_current_mirror = 0,
- .diversity_delay = 0,
-
- .output_mode = OUTMODE_MPEG2_FIFO,
- .enMpegOutput = 1,
-};
-
static const struct dib0090_config nim7090_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
@@ -2649,47 +2748,11 @@ static const struct dib0090_config nim7090_dib0090_config = {
.in_soc = 1,
};
-static const struct dib0090_config tfe7090e_dib0090_config = {
- .io.clock_khz = 12000,
- .io.pll_bypass = 0,
- .io.pll_range = 0,
- .io.pll_prediv = 3,
- .io.pll_loopdiv = 6,
- .io.adc_clock_ratio = 0,
- .io.pll_int_loop_filt = 0,
- .reset = dib7090_tuner_sleep,
- .sleep = dib7090_tuner_sleep,
-
- .freq_offset_khz_uhf = 0,
- .freq_offset_khz_vhf = 0,
-
- .get_adc_power = dib7090_get_adc_power,
-
- .clkouttobamse = 1,
- .analog_output = 0,
-
- .wbd_vhf_offset = 0,
- .wbd_cband_offset = 0,
- .use_pwm_agc = 1,
- .clkoutdrive = 0,
-
- .fref_clock_ratio = 0,
-
- .wbd = dib7090e_wbd_table,
-
- .ls_cfg_pad_drv = 0,
- .data_tx_drv = 0,
- .low_if = NULL,
- .in_soc = 1,
- .force_cband_input = 1,
- .is_dib7090e = 1,
-};
-
-static struct dib7000p_config tfe7790e_dib7000p_config = {
+static struct dib7000p_config tfe7790p_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = dib7090e_update_lna,
+ .update_lna = tfe7790p_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2713,7 +2776,7 @@ static struct dib7000p_config tfe7790e_dib7000p_config = {
.enMpegOutput = 1,
};
-static const struct dib0090_config tfe7790e_dib0090_config = {
+static const struct dib0090_config tfe7790p_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
.io.pll_range = 0,
@@ -2739,14 +2802,14 @@ static const struct dib0090_config tfe7790e_dib0090_config = {
.fref_clock_ratio = 0,
- .wbd = dib7090e_wbd_table,
+ .wbd = dib7090_wbd_table,
.ls_cfg_pad_drv = 0,
.data_tx_drv = 0,
.low_if = NULL,
.in_soc = 1,
- .force_cband_input = 1,
- .is_dib7090e = 1,
+ .force_cband_input = 0,
+ .is_dib7090e = 0,
.force_crystal_mode = 1,
};
@@ -2942,37 +3005,11 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap)
-{
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
- 1, 0x10, &tfe7090e_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
- __func__);
- return -ENODEV;
- }
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
- 0x80, &tfe7090e_dib7000p_config);
-
- return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
+static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
- /* The TFE7790E requires the dib0700 to not be in master mode */
+ /* The TFE7790P requires the dib0700 to not be in master mode */
st->disable_streaming_master_mode = 1;
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
@@ -2988,42 +3025,25 @@ static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
- 1, 0x10, &tfe7790e_dib7000p_config) != 0) {
+ 1, 0x10, &tfe7790p_dib7000p_config) != 0) {
err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
__func__);
return -ENODEV;
}
adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
- 0x80, &tfe7790e_dib7000p_config);
+ 0x80, &tfe7790p_dib7000p_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
-static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap)
-{
- struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c =
- dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
- if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
- &tfe7790e_dib0090_config) == NULL)
- return -ENODEV;
-
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
- st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
- adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
- return 0;
-}
-
-static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap)
+static int tfe7790p_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c =
dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
- &tfe7090e_dib0090_config) == NULL)
+ &tfe7790p_dib0090_config) == NULL)
return -ENODEV;
dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
@@ -3566,10 +3586,9 @@ struct usb_device_id dib0700_usb_id_table[] = {
/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) },
-/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
- { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790P) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
+/* 80 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3880,7 +3899,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
{ "Elgato EyeTV DTT rev. 2",
- { &dib0700_usb_id_table[81], NULL },
+ { &dib0700_usb_id_table[80], NULL },
{ NULL },
},
},
@@ -4697,48 +4716,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.pid_filter_count = 32,
.pid_filter = stk70x0p_pid_filter,
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = tfe7090e_frontend_attach,
- .tuner_attach = tfe7090e_tuner_attach,
-
- DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
- } },
-
- .size_of_priv =
- sizeof(struct dib0700_adapter_state),
- },
- },
-
- .num_device_descs = 1,
- .devices = {
- { "DiBcom TFE7090E reference design",
- { &dib0700_usb_id_table[78], NULL },
- { NULL },
- },
- },
-
- .rc.core = {
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
- .module_name = "dib0700",
- .rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_BIT_RC5 |
- RC_BIT_RC6_MCE |
- RC_BIT_NEC,
- .change_protocol = dib0700_change_protocol,
- },
- }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER |
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .pid_filter_count = 32,
- .pid_filter = stk70x0p_pid_filter,
- .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = tfe7790e_frontend_attach,
- .tuner_attach = tfe7790e_tuner_attach,
+ .frontend_attach = tfe7790p_frontend_attach,
+ .tuner_attach = tfe7790p_tuner_attach,
DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
} },
@@ -4750,8 +4729,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.num_device_descs = 1,
.devices = {
- { "DiBcom TFE7790E reference design",
- { &dib0700_usb_id_table[79], NULL },
+ { "DiBcom TFE7790P reference design",
+ { &dib0700_usb_id_table[78], NULL },
{ NULL },
},
},
@@ -4792,7 +4771,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.num_device_descs = 1,
.devices = {
{ "DiBcom TFE8096P reference design",
- { &dib0700_usb_id_table[80], NULL },
+ { &dib0700_usb_id_table[79], NULL },
{ NULL },
},
},
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index af0d4321845..c2dded92f1d 100644
--- a/drivers/media/usb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -8,6 +8,8 @@
*
* see Documentation/dvb/README.dvb-usb for more information
*/
+
+#include <linux/kconfig.h>
#include "dibusb.h"
static int debug;
@@ -232,8 +234,7 @@ static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
.agc2_slope2 = 0x1e,
};
-#if defined(CONFIG_DVB_DIB3000MC) || \
- (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB3000MC)
static struct dib3000mc_config mod3000p_dib3000p_config = {
&dib3000p_panasonic_agc_config,
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 9578a6761f1..6e237b6dd0a 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -29,7 +29,6 @@
#include "stb6100.h"
#include "stb6100_proc.h"
#include "m88rs2000.h"
-#include "ts2020.h"
#ifndef USB_PID_DW2102
#define USB_PID_DW2102 0x2102
@@ -79,6 +78,10 @@
#define USB_PID_TEVII_S632 0xd632
#endif
+#ifndef USB_PID_GOTVIEW_SAT_HD
+#define USB_PID_GOTVIEW_SAT_HD 0x5456
+#endif
+
#define DW210X_READ_MSG 0
#define DW210X_WRITE_MSG 1
@@ -1548,6 +1551,8 @@ enum dw2102_table_entry {
X3M_SPC1400HD,
TEVII_S421,
TEVII_S632,
+ TERRATEC_CINERGY_S2_R2,
+ GOTVIEW_SAT_HD,
};
static struct usb_device_id dw2102_table[] = {
@@ -1568,6 +1573,8 @@ static struct usb_device_id dw2102_table[] = {
[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
[TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)},
[TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)},
+ [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)},
+ [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)},
{ }
};
@@ -1968,7 +1975,7 @@ static struct dvb_usb_device_properties su3000_properties = {
}},
}
},
- .num_device_descs = 3,
+ .num_device_descs = 5,
.devices = {
{ "SU3000HD DVB-S USB2.0",
{ &dw2102_table[GENIATECH_SU3000], NULL },
@@ -1982,6 +1989,14 @@ static struct dvb_usb_device_properties su3000_properties = {
{ &dw2102_table[X3M_SPC1400HD], NULL },
{ NULL },
},
+ { "Terratec Cinergy S2 USB HD Rev.2",
+ { &dw2102_table[TERRATEC_CINERGY_S2_R2], NULL },
+ { NULL },
+ },
+ { "GOTVIEW Satellite HD",
+ { &dw2102_table[GOTVIEW_SAT_HD], NULL },
+ { NULL },
+ },
}
};
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index 92afeb20650..c2b635d6a17 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -68,20 +68,20 @@ static inline int m920x_write_seq(struct usb_device *udev, u8 request,
struct m920x_inits *seq)
{
int ret;
- while (seq->address) {
+ do {
ret = m920x_write(udev, request, seq->data, seq->address);
if (ret != 0)
return ret;
seq++;
- }
+ } while (seq->address);
- return ret;
+ return 0;
}
static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
{
- int ret = 0, i, epi, flags = 0;
+ int ret, i, epi, flags = 0;
int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
@@ -124,7 +124,7 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
}
}
- return ret;
+ return 0;
}
static int m920x_init_ep(struct usb_interface *intf)
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index c754a80a8d8..ca5ee6aceb6 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -46,6 +46,7 @@ config VIDEO_EM28XX_DVB
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
---help---
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
index 634fb920dd3..ad6d4855794 100644
--- a/drivers/media/usb/em28xx/Makefile
+++ b/drivers/media/usb/em28xx/Makefile
@@ -1,5 +1,5 @@
em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y += em28xx-core.o em28xx-vbi.o
+em28xx-y += em28xx-core.o em28xx-vbi.o em28xx-camera.o
em28xx-alsa-objs := em28xx-audio.o
em28xx-rc-objs := em28xx-input.o
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
new file mode 100644
index 00000000000..73cc50afa5e
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -0,0 +1,434 @@
+/*
+ em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices
+
+ Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org>
+ Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/i2c.h>
+#include <media/soc_camera.h>
+#include <media/mt9v011.h>
+#include <media/v4l2-common.h>
+
+#include "em28xx.h"
+
+
+/* Possible i2c addresses of Micron sensors */
+static unsigned short micron_sensor_addrs[] = {
+ 0xb8 >> 1, /* MT9V111, MT9V403 */
+ 0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */
+ 0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */
+ I2C_CLIENT_END
+};
+
+/* Possible i2c addresses of Omnivision sensors */
+static unsigned short omnivision_sensor_addrs[] = {
+ 0x42 >> 1, /* OV7725, OV7670/60/48 */
+ 0x60 >> 1, /* OV2640, OV9650/53/55 */
+ I2C_CLIENT_END
+};
+
+
+static struct soc_camera_link camlink = {
+ .bus_id = 0,
+ .flags = 0,
+ .module_name = "em28xx",
+};
+
+
+/* FIXME: Should be replaced by a proper mt9m111 driver */
+static int em28xx_initialize_mt9m111(struct em28xx *dev)
+{
+ int i;
+ unsigned char regs[][3] = {
+ { 0x0d, 0x00, 0x01, }, /* reset and use defaults */
+ { 0x0d, 0x00, 0x00, },
+ { 0x0a, 0x00, 0x21, },
+ { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ &regs[i][0], 3);
+
+ return 0;
+}
+
+
+/* FIXME: Should be replaced by a proper mt9m001 driver */
+static int em28xx_initialize_mt9m001(struct em28xx *dev)
+{
+ int i;
+ unsigned char regs[][3] = {
+ { 0x0d, 0x00, 0x01, },
+ { 0x0d, 0x00, 0x00, },
+ { 0x04, 0x05, 0x00, }, /* hres = 1280 */
+ { 0x03, 0x04, 0x00, }, /* vres = 1024 */
+ { 0x20, 0x11, 0x00, },
+ { 0x06, 0x00, 0x10, },
+ { 0x2b, 0x00, 0x24, },
+ { 0x2e, 0x00, 0x24, },
+ { 0x35, 0x00, 0x24, },
+ { 0x2d, 0x00, 0x20, },
+ { 0x2c, 0x00, 0x20, },
+ { 0x09, 0x0a, 0xd4, },
+ { 0x35, 0x00, 0x57, },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ &regs[i][0], 3);
+
+ return 0;
+}
+
+
+/*
+ * Probes Micron sensors with 8 bit address and 16 bit register width
+ */
+static int em28xx_probe_sensor_micron(struct em28xx *dev)
+{
+ int ret, i;
+ char *name;
+ u8 reg;
+ __be16 id_be;
+ u16 id;
+
+ struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
+
+ dev->em28xx_sensor = EM28XX_NOSENSOR;
+ for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
+ client.addr = micron_sensor_addrs[i];
+ /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
+ /* Read chip ID from register 0x00 */
+ reg = 0x00;
+ ret = i2c_master_send(&client, &reg, 1);
+ if (ret < 0) {
+ if (ret != -ENODEV)
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id = be16_to_cpu(id_be);
+ /* Read chip ID from register 0xff */
+ reg = 0xff;
+ ret = i2c_master_send(&client, &reg, 1);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ /* Validate chip ID to be sure we have a Micron device */
+ if (id != be16_to_cpu(id_be))
+ continue;
+ /* Check chip ID */
+ id = be16_to_cpu(id_be);
+ switch (id) {
+ case 0x1222:
+ name = "MT9V012"; /* MI370 */ /* 640x480 */
+ break;
+ case 0x1229:
+ name = "MT9V112"; /* 640x480 */
+ break;
+ case 0x1433:
+ name = "MT9M011"; /* 1280x1024 */
+ break;
+ case 0x143a: /* found in the ECS G200 */
+ name = "MT9M111"; /* MI1310 */ /* 1280x1024 */
+ dev->em28xx_sensor = EM28XX_MT9M111;
+ break;
+ case 0x148c:
+ name = "MT9M112"; /* MI1320 */ /* 1280x1024 */
+ break;
+ case 0x1511:
+ name = "MT9D011"; /* MI2010 */ /* 1600x1200 */
+ break;
+ case 0x8232:
+ case 0x8243: /* rev B */
+ name = "MT9V011"; /* MI360 */ /* 640x480 */
+ dev->em28xx_sensor = EM28XX_MT9V011;
+ break;
+ case 0x8431:
+ name = "MT9M001"; /* 1280x1024 */
+ dev->em28xx_sensor = EM28XX_MT9M001;
+ break;
+ default:
+ em28xx_info("unknown Micron sensor detected: 0x%04x\n",
+ id);
+ return 0;
+ }
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR)
+ em28xx_info("unsupported sensor detected: %s\n", name);
+ else
+ em28xx_info("sensor %s detected\n", name);
+
+ dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+/*
+ * Probes Omnivision sensors with 8 bit address and register width
+ */
+static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
+{
+ int ret, i;
+ char *name;
+ u8 reg;
+ u16 id;
+ struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
+
+ dev->em28xx_sensor = EM28XX_NOSENSOR;
+ /* NOTE: these devices have the register auto incrementation disabled
+ * by default, so we have to use single byte reads ! */
+ for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
+ client.addr = omnivision_sensor_addrs[i];
+ /* Read manufacturer ID from registers 0x1c-0x1d (BE) */
+ reg = 0x1c;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ if (ret != -ENODEV)
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id = ret << 8;
+ reg = 0x1d;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id += ret;
+ /* Check manufacturer ID */
+ if (id != 0x7fa2)
+ continue;
+ /* Read product ID from registers 0x0a-0x0b (BE) */
+ reg = 0x0a;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id = ret << 8;
+ reg = 0x0b;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id += ret;
+ /* Check product ID */
+ switch (id) {
+ case 0x2642:
+ name = "OV2640";
+ dev->em28xx_sensor = EM28XX_OV2640;
+ break;
+ case 0x7648:
+ name = "OV7648";
+ break;
+ case 0x7660:
+ name = "OV7660";
+ break;
+ case 0x7673:
+ name = "OV7670";
+ break;
+ case 0x7720:
+ name = "OV7720";
+ break;
+ case 0x7721:
+ name = "OV7725";
+ break;
+ case 0x9648: /* Rev 2 */
+ case 0x9649: /* Rev 3 */
+ name = "OV9640";
+ break;
+ case 0x9650:
+ case 0x9652: /* OV9653 */
+ name = "OV9650";
+ break;
+ case 0x9656: /* Rev 4 */
+ case 0x9657: /* Rev 5 */
+ name = "OV9655";
+ break;
+ default:
+ em28xx_info("unknown OmniVision sensor detected: 0x%04x\n",
+ id);
+ return 0;
+ }
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR)
+ em28xx_info("unsupported sensor detected: %s\n", name);
+ else
+ em28xx_info("sensor %s detected\n", name);
+
+ dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+int em28xx_detect_sensor(struct em28xx *dev)
+{
+ int ret;
+
+ ret = em28xx_probe_sensor_micron(dev);
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0)
+ ret = em28xx_probe_sensor_omnivision(dev);
+
+ /*
+ * NOTE: the Windows driver also probes i2c addresses
+ * 0x22 (Samsung ?) and 0x66 (Kodak ?)
+ */
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) {
+ em28xx_info("No sensor detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int em28xx_init_camera(struct em28xx *dev)
+{
+ switch (dev->em28xx_sensor) {
+ case EM28XX_MT9V011:
+ {
+ struct mt9v011_platform_data pdata;
+ struct i2c_board_info mt9v011_info = {
+ .type = "mt9v011",
+ .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+ .platform_data = &pdata,
+ };
+
+ dev->sensor_xres = 640;
+ dev->sensor_yres = 480;
+
+ /*
+ * FIXME: mt9v011 uses I2S speed as xtal clk - at least with
+ * the Silvercrest cam I have here for testing - for higher
+ * resolutions, a high clock cause horizontal artifacts, so we
+ * need to use a lower xclk frequency.
+ * Yet, it would be possible to adjust xclk depending on the
+ * desired resolution, since this affects directly the
+ * frame rate.
+ */
+ dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
+ dev->sensor_xtal = 4300000;
+ pdata.xtal = dev->sensor_xtal;
+ if (NULL ==
+ v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &mt9v011_info, NULL))
+ return -ENODEV;
+ /* probably means GRGB 16 bit bayer */
+ dev->vinmode = 0x0d;
+ dev->vinctl = 0x00;
+
+ break;
+ }
+ case EM28XX_MT9M001:
+ dev->sensor_xres = 1280;
+ dev->sensor_yres = 1024;
+
+ em28xx_initialize_mt9m001(dev);
+
+ /* probably means BGGR 16 bit bayer */
+ dev->vinmode = 0x0c;
+ dev->vinctl = 0x00;
+
+ break;
+ case EM28XX_MT9M111:
+ dev->sensor_xres = 640;
+ dev->sensor_yres = 512;
+
+ dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
+ em28xx_initialize_mt9m111(dev);
+
+ dev->vinmode = 0x0a;
+ dev->vinctl = 0x00;
+
+ break;
+ case EM28XX_OV2640:
+ {
+ struct v4l2_subdev *subdev;
+ struct i2c_board_info ov2640_info = {
+ .type = "ov2640",
+ .flags = I2C_CLIENT_SCCB,
+ .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+ .platform_data = &camlink,
+ };
+ struct v4l2_mbus_framefmt fmt;
+
+ /*
+ * FIXME: sensor supports resolutions up to 1600x1200, but
+ * resolution setting/switching needs to be modified to
+ * - switch sensor output resolution (including further
+ * configuration changes)
+ * - adjust bridge xclk
+ * - disable 16 bit (12 bit) output formats on high resolutions
+ */
+ dev->sensor_xres = 640;
+ dev->sensor_yres = 480;
+
+ subdev =
+ v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &ov2640_info, NULL);
+
+ fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt.width = 640;
+ fmt.height = 480;
+ v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt);
+
+ /* NOTE: for UXGA=1600x1200 switch to 12MHz */
+ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
+ dev->vinmode = 0x08;
+ dev->vinctl = 0x00;
+
+ break;
+ }
+ case EM28XX_NOSENSOR:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 54a03b20de6..83bfbe4c980 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -34,7 +34,6 @@
#include <media/saa7115.h>
#include <media/tvp5150.h>
#include <media/tvaudio.h>
-#include <media/mt9v011.h>
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
@@ -345,6 +344,18 @@ static struct em28xx_reg_seq pctv_460e[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
+ {EM2874_R80_GPIO, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO, 0xfd, 0xff, 10}, /* xc5000 reset */
+ {EM2874_R80_GPIO, 0xf9, 0xff, 35},
+ {EM2874_R80_GPIO, 0xfd, 0xff, 10},
+ {EM2874_R80_GPIO, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO, 0xfe, 0xff, 10},
+ {EM2874_R80_GPIO, 0xbe, 0xff, 10},
+ {EM2874_R80_GPIO, 0xfe, 0xff, 20},
+ { -1, -1, -1, -1},
+};
+
#if 0
static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
{EM2874_R80_GPIO, 0x6f, 0xff, 10},
@@ -958,8 +969,8 @@ struct em28xx_board em28xx_boards[] = {
#else
.tuner_type = TUNER_ABSENT,
#endif
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
[EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = {
@@ -974,17 +985,27 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
#endif
.ir_codes = RC_MAP_HAUPPAUGE,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
+ [EM2884_BOARD_C3TECH_DIGITAL_DUO] = {
+ .name = "C3 Tech Digital Duo HDTV/SDTV USB",
+ .has_dvb = 1,
+ /* FIXME: Add analog support - need a saa7136 driver */
+ .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */
+ .ir_codes = RC_MAP_EMPTY,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE,
+ .dvb_gpio = c3tech_digital_duo_digital,
+ },
[EM2884_BOARD_CINERGY_HTC_STICK] = {
.name = "Terratec Cinergy HTC Stick",
.has_dvb = 1,
.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
.tuner_type = TUNER_ABSENT,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
@@ -1404,8 +1425,8 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2874_BOARD_LEADERSHIP_ISDBT] = {
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_100_KHZ,
.xclk = EM28XX_XCLK_FREQUENCY_10MHZ,
.name = "EM2874 Leadership ISDBT",
@@ -1917,8 +1938,8 @@ struct em28xx_board em28xx_boards[] = {
* Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
[EM28174_BOARD_PCTV_290E] = {
.name = "PCTV nanoStick T2 290e",
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_290e,
.has_dvb = 1,
@@ -1927,8 +1948,8 @@ struct em28xx_board em28xx_boards[] = {
/* 2013:024f PCTV DVB-S2 Stick 460e
* Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */
[EM28174_BOARD_PCTV_460E] = {
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
.name = "PCTV DVB-S2 Stick (460e)",
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_460e,
@@ -1958,8 +1979,9 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_gpio = maxmedia_ub425_tc,
.has_dvb = 1,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .ir_codes = RC_MAP_REDDO,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
/* 2304:0242 PCTV QuatroStick (510e)
@@ -1970,8 +1992,8 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = pctv_510e,
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
/* 2013:0251 PCTV QuatroStick nano (520e)
@@ -1982,8 +2004,8 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = pctv_520e,
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
[EM2884_BOARD_TERRATEC_HTC_USB_XS] = {
@@ -1991,8 +2013,8 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
.tuner_type = TUNER_ABSENT,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
};
@@ -2144,6 +2166,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM28174_BOARD_PCTV_460E },
{ USB_DEVICE(0x2040, 0x1605),
.driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C },
+ { USB_DEVICE(0x1b80, 0xe755),
+ .driver_info = EM2884_BOARD_C3TECH_DIGITAL_DUO },
{ USB_DEVICE(0xeb1a, 0x5006),
.driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
{ USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
@@ -2183,6 +2207,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
{0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
};
+/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
static unsigned short saa711x_addrs[] = {
@@ -2204,8 +2229,9 @@ static unsigned short msp3400_addrs[] = {
int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
{
+ struct em28xx_i2c_bus *i2c_bus = ptr;
+ struct em28xx *dev = i2c_bus->dev;
int rc = 0;
- struct em28xx *dev = ptr;
if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000)
return 0;
@@ -2233,145 +2259,9 @@ static inline void em28xx_set_model(struct em28xx *dev)
if (!dev->board.i2c_speed)
dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_100_KHZ;
-}
-
-
-/* FIXME: Should be replaced by a proper mt9m111 driver */
-static int em28xx_initialize_mt9m111(struct em28xx *dev)
-{
- int i;
- unsigned char regs[][3] = {
- { 0x0d, 0x00, 0x01, }, /* reset and use defaults */
- { 0x0d, 0x00, 0x00, },
- { 0x0a, 0x00, 0x21, },
- { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */
- };
-
- for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
-
- return 0;
-}
-
-
-/* FIXME: Should be replaced by a proper mt9m001 driver */
-static int em28xx_initialize_mt9m001(struct em28xx *dev)
-{
- int i;
- unsigned char regs[][3] = {
- { 0x0d, 0x00, 0x01, },
- { 0x0d, 0x00, 0x00, },
- { 0x04, 0x05, 0x00, }, /* hres = 1280 */
- { 0x03, 0x04, 0x00, }, /* vres = 1024 */
- { 0x20, 0x11, 0x00, },
- { 0x06, 0x00, 0x10, },
- { 0x2b, 0x00, 0x24, },
- { 0x2e, 0x00, 0x24, },
- { 0x35, 0x00, 0x24, },
- { 0x2d, 0x00, 0x20, },
- { 0x2c, 0x00, 0x20, },
- { 0x09, 0x0a, 0xd4, },
- { 0x35, 0x00, 0x57, },
- };
-
- for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
-
- return 0;
-}
-
-/* HINT method: webcam I2C chips
- *
- * This method works for webcams with Micron sensors
- */
-static int em28xx_hint_sensor(struct em28xx *dev)
-{
- int rc;
- char *sensor_name;
- unsigned char cmd;
- __be16 version_be;
- u16 version;
-
- /* Micron sensor detection */
- dev->i2c_client.addr = 0xba >> 1;
- cmd = 0;
- i2c_master_send(&dev->i2c_client, &cmd, 1);
- rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2);
- if (rc != 2)
- return -EINVAL;
-
- version = be16_to_cpu(version_be);
- switch (version) {
- case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */
- case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */
- dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
- em28xx_set_model(dev);
-
- sensor_name = "mt9v011";
- dev->em28xx_sensor = EM28XX_MT9V011;
- dev->sensor_xres = 640;
- dev->sensor_yres = 480;
- /*
- * FIXME: mt9v011 uses I2S speed as xtal clk - at least with
- * the Silvercrest cam I have here for testing - for higher
- * resolutions, a high clock cause horizontal artifacts, so we
- * need to use a lower xclk frequency.
- * Yet, it would be possible to adjust xclk depending on the
- * desired resolution, since this affects directly the
- * frame rate.
- */
- dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
- dev->sensor_xtal = 4300000;
-
- /* probably means GRGB 16 bit bayer */
- dev->vinmode = 0x0d;
- dev->vinctl = 0x00;
-
- break;
-
- case 0x143a: /* MT9M111 as found in the ECS G200 */
- dev->model = EM2750_BOARD_UNKNOWN;
- em28xx_set_model(dev);
-
- sensor_name = "mt9m111";
- dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
- dev->em28xx_sensor = EM28XX_MT9M111;
- em28xx_initialize_mt9m111(dev);
- dev->sensor_xres = 640;
- dev->sensor_yres = 512;
-
- dev->vinmode = 0x0a;
- dev->vinctl = 0x00;
-
- break;
-
- case 0x8431:
- dev->model = EM2750_BOARD_UNKNOWN;
- em28xx_set_model(dev);
-
- sensor_name = "mt9m001";
- dev->em28xx_sensor = EM28XX_MT9M001;
- em28xx_initialize_mt9m001(dev);
- dev->sensor_xres = 1280;
- dev->sensor_yres = 1024;
-
- /* probably means BGGR 16 bit bayer */
- dev->vinmode = 0x0c;
- dev->vinctl = 0x00;
-
- break;
- default:
- printk("Unknown Micron Sensor 0x%04x\n", version);
- return -EINVAL;
- }
-
- /* Setup webcam defaults */
- em28xx_pre_card_setup(dev);
- em28xx_errdev("Sensor is %s, using model %s entry.\n",
- sensor_name, em28xx_boards[dev->model].name);
-
- return 0;
+ /* Should be initialized early, for I2C to work */
+ dev->def_i2c_bus = dev->board.def_i2c_bus;
}
/* Since em28xx_pre_card_setup() requires a proper dev->model,
@@ -2599,6 +2489,18 @@ static int em28xx_hint_board(struct em28xx *dev)
{
int i;
+ if (dev->board.is_webcam) {
+ if (dev->em28xx_sensor == EM28XX_MT9V011) {
+ dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
+ } else if (dev->em28xx_sensor == EM28XX_MT9M001 ||
+ dev->em28xx_sensor == EM28XX_MT9M111) {
+ dev->model = EM2750_BOARD_UNKNOWN;
+ }
+ /* FIXME: IMPROVE ! */
+
+ return 0;
+ }
+
/* HINT method: EEPROM
*
* This method works only for boards with eeprom.
@@ -2638,7 +2540,7 @@ static int em28xx_hint_board(struct em28xx *dev)
/* user did not request i2c scanning => do it now */
if (!dev->i2c_hash)
- em28xx_do_i2c_scan(dev);
+ em28xx_do_i2c_scan(dev, dev->def_i2c_bus);
for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) {
if (dev->i2c_hash == em28xx_i2c_hash[i].hash) {
@@ -2684,16 +2586,16 @@ static void em28xx_card_setup(struct em28xx *dev)
* If sensor is not found, then it isn't a webcam.
*/
if (dev->board.is_webcam) {
- if (em28xx_hint_sensor(dev) < 0)
+ if (em28xx_detect_sensor(dev) < 0)
dev->board.is_webcam = 0;
else
dev->progressive = 1;
}
- if (!dev->board.is_webcam) {
- switch (dev->model) {
- case EM2820_BOARD_UNKNOWN:
- case EM2800_BOARD_UNKNOWN:
+ switch (dev->model) {
+ case EM2750_BOARD_UNKNOWN:
+ case EM2820_BOARD_UNKNOWN:
+ case EM2800_BOARD_UNKNOWN:
/*
* The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
*
@@ -2714,9 +2616,8 @@ static void em28xx_card_setup(struct em28xx *dev)
em28xx_pre_card_setup(dev);
}
break;
- default:
- em28xx_set_model(dev);
- }
+ default:
+ em28xx_set_model(dev);
}
em28xx_info("Identified as %s (card=%d)\n",
@@ -2736,15 +2637,19 @@ static void em28xx_card_setup(struct em28xx *dev)
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
{
struct tveeprom tv;
+
+ if (dev->eedata == NULL)
+ break;
#if defined(CONFIG_MODULES) && defined(MODULE)
request_module("tveeprom");
#endif
/* Call first TVeeprom */
- dev->i2c_client.addr = 0xa0 >> 1;
- tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+ dev->i2c_client[dev->def_i2c_bus].addr = 0xa0 >> 1;
+ tveeprom_hauppauge_analog(&dev->i2c_client[dev->def_i2c_bus], &tv, dev->eedata);
dev->tuner_type = tv.tuner_type;
@@ -2791,7 +2696,7 @@ static void em28xx_card_setup(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break;
-/*
+ /*
* The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR.
*
* This occurs because they share identical USB vendor and
@@ -2826,51 +2731,41 @@ static void em28xx_card_setup(struct em28xx *dev)
"addresses)\n\n");
}
+ /* Free eeprom data memory */
+ kfree(dev->eedata);
+ dev->eedata = NULL;
+
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
/* request some modules */
if (dev->board.has_msp34xx)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tvp5150", 0, tvp5150_addrs);
- if (dev->em28xx_sensor == EM28XX_MT9V011) {
- struct mt9v011_platform_data pdata;
- struct i2c_board_info mt9v011_info = {
- .type = "mt9v011",
- .addr = 0xba >> 1,
- .platform_data = &pdata,
- };
-
- pdata.xtal = dev->sensor_xtal;
- v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
- &mt9v011_info, NULL);
- }
-
-
if (dev->board.adecoder == EM28XX_TVAUDIO)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tvaudio", dev->board.tvaudio_addr, NULL);
if (dev->board.tuner_type != TUNER_ABSENT) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tuner", dev->board.radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner",
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
@@ -2878,18 +2773,20 @@ static void em28xx_card_setup(struct em28xx *dev)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner",
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
0, v4l2_i2c_tuner_addrs(type));
if (sd)
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tuner", dev->tuner_addr, NULL);
}
}
em28xx_tuner_setup(dev);
+
+ em28xx_init_camera(dev);
}
@@ -2914,7 +2811,8 @@ static void request_module_async(struct work_struct *work)
if (dev->board.has_dvb)
request_module("em28xx-dvb");
- if ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir)
+ if (dev->board.has_snapshot_button ||
+ ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir))
request_module("em28xx-rc");
#endif /* CONFIG_MODULES */
}
@@ -2941,7 +2839,9 @@ void em28xx_release_resources(struct em28xx *dev)
em28xx_release_analog_resources(dev);
- em28xx_i2c_unregister(dev);
+ if (dev->def_i2c_bus)
+ em28xx_i2c_unregister(dev, 1);
+ em28xx_i2c_unregister(dev, 0);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
@@ -3002,8 +2902,23 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
case CHIP_ID_EM2750:
chip_name = "em2750";
break;
+ case CHIP_ID_EM2765:
+ chip_name = "em2765";
+ dev->wait_after_write = 0;
+ dev->is_em25xx = 1;
+ dev->eeprom_addrwidth_16bit = 1;
+ break;
case CHIP_ID_EM2820:
chip_name = "em2710/2820";
+ if (le16_to_cpu(dev->udev->descriptor.idVendor)
+ == 0xeb1a) {
+ __le16 idProd = dev->udev->descriptor.idProduct;
+ if (le16_to_cpu(idProd) == 0x2710)
+ chip_name = "em2710";
+ else if (le16_to_cpu(idProd) == 0x2820)
+ chip_name = "em2820";
+ }
+ /* NOTE: the em2820 is used in webcams, too ! */
break;
case CHIP_ID_EM2840:
chip_name = "em2840";
@@ -3019,11 +2934,13 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
chip_name = "em2874";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
break;
case CHIP_ID_EM28174:
chip_name = "em28174";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
break;
case CHIP_ID_EM2883:
chip_name = "em2882/3";
@@ -3033,6 +2950,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
chip_name = "em2884";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
break;
default:
printk(KERN_INFO DRIVER_NAME
@@ -3066,14 +2984,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
em28xx_pre_card_setup(dev);
- if (dev->chip_id == CHIP_ID_EM2820) {
- if (dev->board.is_webcam)
- chip_name = "em2710";
- else
- chip_name = "em2820";
- snprintf(dev->name, sizeof(dev->name), "%s #%d", chip_name, dev->devno);
- }
-
if (!dev->board.is_em2800) {
/* Resets I2C speed */
retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
@@ -3091,17 +3001,37 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
return retval;
}
- v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_handler_init(hdl, 8);
dev->v4l2_dev.ctrl_handler = hdl;
- /* register i2c bus */
- retval = em28xx_i2c_register(dev);
+ rt_mutex_init(&dev->i2c_bus_lock);
+
+ /* register i2c bus 0 */
+ if (dev->board.is_em2800)
+ retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM2800);
+ else
+ retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX);
if (retval < 0) {
- em28xx_errdev("%s: em28xx_i2c_register - error [%d]!\n",
+ em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
__func__, retval);
goto unregister_dev;
}
+ /* register i2c bus 1 */
+ if (dev->def_i2c_bus) {
+ if (dev->is_em25xx)
+ retval = em28xx_i2c_register(dev, 1,
+ EM28XX_I2C_ALGO_EM25XX_BUS_B);
+ else
+ retval = em28xx_i2c_register(dev, 1,
+ EM28XX_I2C_ALGO_EM28XX);
+ if (retval < 0) {
+ em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
+ __func__, retval);
+ goto unregister_dev;
+ }
+ }
+
/*
* Default format, used for tvp5150 or saa711x output formats
*/
@@ -3160,11 +3090,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
msleep(3);
}
- v4l2_ctrl_handler_setup(&dev->ctrl_handler);
- retval = dev->ctrl_handler.error;
- if (retval)
- goto fail;
-
retval = em28xx_register_analog_devices(dev);
if (retval < 0) {
goto fail;
@@ -3176,7 +3101,9 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
return 0;
fail:
- em28xx_i2c_unregister(dev);
+ if (dev->def_i2c_bus)
+ em28xx_i2c_unregister(dev, 1);
+ em28xx_i2c_unregister(dev, 0);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
unregister_dev:
@@ -3292,14 +3219,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev->analog_ep_bulk =
e->bEndpointAddress;
} else {
- has_dvb = true;
if (usb_endpoint_xfer_isoc(e)) {
- dev->dvb_ep_isoc = e->bEndpointAddress;
if (size > dev->dvb_max_pkt_size_isoc) {
+ has_dvb = true; /* see NOTE (~) */
+ dev->dvb_ep_isoc = e->bEndpointAddress;
dev->dvb_max_pkt_size_isoc = size;
dev->dvb_alt_isoc = i;
}
} else {
+ has_dvb = true;
dev->dvb_ep_bulk = e->bEndpointAddress;
}
}
@@ -3326,6 +3254,12 @@ static int em28xx_usb_probe(struct usb_interface *interface,
* so far. But there might be devices for which this
* logic is not sufficient...
*/
+ /*
+ * NOTE (~): some manufacturers (e.g. Terratec) disable
+ * endpoints by setting wMaxPacketSize to 0 bytes for
+ * all alt settings. So far, we've seen this for
+ * DVB isoc endpoints only.
+ */
}
}
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index aaedd11791f..a802128ce9c 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -607,12 +607,12 @@ EXPORT_SYMBOL_GPL(em28xx_audio_setup);
int em28xx_colorlevels_set_default(struct em28xx *dev)
{
- em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */
- em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */
- em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */
- em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00);
+ em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
@@ -681,6 +681,11 @@ int em28xx_vbi_supported(struct em28xx *dev)
if (disable_vbi == 1)
return 0;
+ if (dev->board.is_webcam)
+ return 0;
+
+ /* FIXME: check subdevices for VBI support */
+
if (dev->chip_id == CHIP_ID_EM2860 ||
dev->chip_id == CHIP_ID_EM2883)
return 1;
@@ -692,12 +697,23 @@ int em28xx_vbi_supported(struct em28xx *dev)
int em28xx_set_outfmt(struct em28xx *dev)
{
int ret;
- u8 vinctrl;
-
- ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
- dev->format->reg | 0x20, 0xff);
+ u8 fmt, vinctrl;
+
+ fmt = dev->format->reg;
+ if (!dev->is_em25xx)
+ fmt |= 0x20;
+ /*
+ * NOTE: it's not clear if this is really needed !
+ * The datasheets say bit 5 is a reserved bit and devices seem to work
+ * fine without it. But the Windows driver sets it for em2710/50+em28xx
+ * devices and we've always been setting it, too.
+ *
+ * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
+ * it's likely used for an additional (compressed ?) format there.
+ */
+ ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
if (ret < 0)
- return ret;
+ return ret;
ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
if (ret < 0)
@@ -751,6 +767,13 @@ static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+
+ /* FIXME: function/meaning of these registers ? */
+ /* FIXME: align width+height to multiples of 4 ?! */
+ if (dev->is_em25xx) {
+ em28xx_write_reg(dev, 0x34, width >> 4);
+ em28xx_write_reg(dev, 0x35, height >> 4);
+ }
}
static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index a81ec2e8cc9..b22f8fed812 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -50,6 +50,7 @@
#include "tda10071.h"
#include "a8293.h"
#include "qt1010.h"
+#include "mb86a20s.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -177,7 +178,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
static int em28xx_start_streaming(struct em28xx_dvb *dvb)
{
int rc;
- struct em28xx *dev = dvb->adapter.priv;
+ struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
+ struct em28xx *dev = i2c_bus->dev;
int dvb_max_packet_size, packet_multiplier, dvb_alt;
if (dev->dvb_xfer_bulk) {
@@ -216,12 +218,11 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
{
- struct em28xx *dev = dvb->adapter.priv;
+ struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
+ struct em28xx *dev = i2c_bus->dev;
em28xx_stop_urbs(dev);
- em28xx_set_mode(dev, EM28XX_SUSPEND);
-
return 0;
}
@@ -269,7 +270,8 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
/* ------------------------------------------------------------------ */
static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
{
- struct em28xx *dev = fe->dvb->priv;
+ struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
+ struct em28xx *dev = i2c_bus->dev;
if (acquire)
return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
@@ -465,10 +467,10 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, hauppauge_hvr930c_end);
msleep(100);
@@ -522,10 +524,10 @@ static void terratec_h5_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_h5_end);
};
@@ -575,10 +577,10 @@ static void terratec_htc_stick_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_htc_stick_end);
};
@@ -633,10 +635,10 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_htc_usb_xs_end);
};
@@ -662,10 +664,10 @@ static void pctv_520e_init(struct em28xx *dev)
{{ 0x01, 0x00, 0x73, 0xaf }, 4},
};
- dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; /* 0x41 */
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
};
static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
@@ -768,9 +770,25 @@ static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
};
static struct qt1010_config em28xx_qt1010_config = {
.i2c_address = 0x62
+};
+static const struct mb86a20s_config c3tech_duo_mb86a20s_config = {
+ .demod_address = 0x10,
+ .is_serial = true,
+};
+
+static struct tda18271_std_map mb86a20s_tda18271_config = {
+ .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, },
};
+static struct tda18271_config c3tech_duo_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_config,
+ .gate = TDA18271_GATE_DIGITAL,
+ .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
+};
+
+
/* ------------------------------------------------------------------ */
static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
@@ -779,7 +797,7 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
struct xc2028_config cfg;
memset(&cfg, 0, sizeof(cfg));
- cfg.i2c_adap = &dev->i2c_adap;
+ cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus];
cfg.i2c_addr = addr;
if (!dev->dvb->fe[0]) {
@@ -824,7 +842,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
if (dvb->fe[1])
dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
- dvb->adapter.priv = dev;
+ dvb->adapter.priv = &dev->i2c_bus[dev->def_i2c_bus];
/* register frontend */
result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
@@ -962,7 +980,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
switch (dev->model) {
case EM2874_BOARD_LEADERSHIP_ISDBT:
dvb->fe[0] = dvb_attach(s921_attach,
- &sharp_isdbt, &dev->i2c_adap);
+ &sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
@@ -976,7 +994,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -985,7 +1003,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_KWORLD_DVB_310U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_with_xc3028,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -996,7 +1014,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_EMPIRE_DUAL_TV:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1009,13 +1027,13 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2882_BOARD_KWORLD_VS_DVBT:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] == NULL) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn't for zl10353, try mt352 */
dvb->fe[0] = dvb_attach(mt352_attach,
&terratec_xs_mt352_cfg,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
}
if (em28xx_attach_xc3028(0x61, dev) < 0) {
@@ -1026,16 +1044,16 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2870_BOARD_KWORLD_355U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_no_i2c_gate_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL)
dvb_attach(qt1010_attach, dvb->fe[0],
- &dev->i2c_adap, &em28xx_qt1010_config);
+ &dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config);
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
dvb->fe[0] = dvb_attach(s5h1409_attach,
&em28xx_s5h1409_with_xc3028,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1044,10 +1062,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2882_BOARD_KWORLD_ATSC_315U:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
- &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
+ &dev->i2c_adap[dev->def_i2c_bus], 0x61, TUNER_THOMSON_DTT761X)) {
result = -EINVAL;
goto out_free;
}
@@ -1056,7 +1074,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
- &dev->i2c_adap, &dev->udev->dev);
+ &dev->i2c_adap[dev->def_i2c_bus], &dev->udev->dev);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1066,10 +1084,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
dvb->fe[0] = dvb_attach(tda10023_attach,
&em28xx_tda10023_config,
- &dev->i2c_adap, 0x48);
+ &dev->i2c_adap[dev->def_i2c_bus], 0x48);
if (dvb->fe[0]) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
- &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
+ &dev->i2c_adap[dev->def_i2c_bus], 0x60, TUNER_PHILIPS_CU1216L)) {
result = -EINVAL;
goto out_free;
}
@@ -1078,10 +1096,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2870_BOARD_KWORLD_A340:
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL)
dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap, &kworld_a340_config);
+ &dev->i2c_adap[dev->def_i2c_bus], &kworld_a340_config);
break;
case EM28174_BOARD_PCTV_290E:
/* set default GPIO0 for LNA, used if GPIOLIB is undefined */
@@ -1089,14 +1107,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
CXD2820R_GPIO_L;
dvb->fe[0] = dvb_attach(cxd2820r_attach,
&em28xx_cxd2820r_config,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&dvb->lna_gpio);
if (dvb->fe[0]) {
/* FE 0 attach tuner */
if (!dvb_attach(tda18271_attach,
dvb->fe[0],
0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
dvb_frontend_detach(dvb->fe[0]);
@@ -1126,7 +1144,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
hauppauge_hvr930c_init(dev);
dvb->fe[0] = dvb_attach(drxk_attach,
- &hauppauge_930c_drxk, &dev->i2c_adap);
+ &hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1144,7 +1162,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
- if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap,
+ if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
&cfg)) {
result = -EINVAL;
goto out_free;
@@ -1157,7 +1175,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2884_BOARD_TERRATEC_H5:
terratec_h5_init(dev);
- dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap);
+ dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1171,7 +1189,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Attach tda18271 to DVB-C frontend */
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
- if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) {
+ if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
result = -EINVAL;
goto out_free;
}
@@ -1179,20 +1197,29 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
break;
+ case EM2884_BOARD_C3TECH_DIGITAL_DUO:
+ dvb->fe[0] = dvb_attach(mb86a20s_attach,
+ &c3tech_duo_mb86a20s_config,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0] != NULL)
+ dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &c3tech_duo_tda18271_config);
+ break;
case EM28174_BOARD_PCTV_460E:
/* attach demod */
dvb->fe[0] = dvb_attach(tda10071_attach,
- &em28xx_tda10071_config, &dev->i2c_adap);
+ &em28xx_tda10071_config, &dev->i2c_adap[dev->def_i2c_bus]);
/* attach SEC */
if (dvb->fe[0])
- dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap,
+ dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_a8293_config);
break;
case EM2874_BOARD_MAXMEDIA_UB425_TC:
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* disable I2C-gate */
@@ -1200,7 +1227,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach tuner */
if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
- &dev->i2c_adap, 0x60)) {
+ &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
goto out_free;
@@ -1218,12 +1245,12 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* attach tuner */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
@@ -1236,7 +1263,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1244,7 +1271,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Attach the demodulator. */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
result = -EINVAL;
goto out_free;
@@ -1255,7 +1282,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1263,7 +1290,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Attach the demodulator. */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
result = -EINVAL;
goto out_free;
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 8532c1d4fd4..4851cc2e4a4 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -5,6 +5,7 @@
Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
+ Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -41,14 +42,6 @@ static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-#define dprintk2(lvl, fmt, args...) \
-do { \
- if (i2c_debug >= lvl) { \
- printk(KERN_DEBUG "%s at %s: " fmt, \
- dev->name, __func__ , ##args); \
- } \
-} while (0)
-
/*
* em2800_i2c_send_bytes()
* send up to 4 bytes to the em2800 i2c device
@@ -76,8 +69,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
/* trigger write */
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
if (ret != 2 + len) {
- em28xx_warn("failed to trigger write to i2c address 0x%x "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
+ addr, ret);
return (ret < 0) ? ret : -EIO;
}
/* wait for completion */
@@ -89,8 +82,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
} else if (ret == 0x94 + len - 1) {
return -ENODEV;
} else if (ret < 0) {
- em28xx_warn("failed to get i2c transfer status from "
- "bridge register (error=%i)\n", ret);
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
+ ret);
return ret;
}
msleep(5);
@@ -118,8 +111,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
buf2[0] = addr;
ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
if (ret != 2) {
- em28xx_warn("failed to trigger read from i2c address 0x%x "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
+ addr, ret);
return (ret < 0) ? ret : -EIO;
}
@@ -132,8 +125,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
} else if (ret == 0x94 + len - 1) {
return -ENODEV;
} else if (ret < 0) {
- em28xx_warn("failed to get i2c transfer status from "
- "bridge register (error=%i)\n", ret);
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
+ ret);
return ret;
}
msleep(5);
@@ -144,9 +137,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
/* get the received message */
ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
if (ret != len) {
- em28xx_warn("reading from i2c device at 0x%x failed: "
- "couldn't get the received message from the bridge "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
+ addr, ret);
return (ret < 0) ? ret : -EIO;
}
for (i = 0; i < len; i++)
@@ -180,19 +172,20 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
if (len < 1 || len > 64)
return -EOPNOTSUPP;
- /* NOTE: limited by the USB ctrl message constraints
- * Zero length reads always succeed, even if no device is connected */
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
/* Write to i2c device */
ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
if (ret != len) {
if (ret < 0) {
- em28xx_warn("writing to i2c device at 0x%x failed "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
return ret;
} else {
- em28xx_warn("%i bytes write to i2c device at 0x%x "
- "requested, but %i bytes written\n",
+ em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
len, addr, ret);
return -EIO;
}
@@ -207,14 +200,16 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
} else if (ret == 0x10) {
return -ENODEV;
} else if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from "
- "bridge (error=%i)\n", ret);
+ em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ ret);
return ret;
}
msleep(5);
- /* NOTE: do we really have to wait for success ?
- Never seen anything else than 0x00 or 0x10
- (even with high payload) ... */
+ /*
+ * NOTE: do we really have to wait for success ?
+ * Never seen anything else than 0x00 or 0x10
+ * (even with high payload) ...
+ */
}
em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
return -EIO;
@@ -230,29 +225,32 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
if (len < 1 || len > 64)
return -EOPNOTSUPP;
- /* NOTE: limited by the USB ctrl message constraints
- * Zero length reads always succeed, even if no device is connected */
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
/* Read data from i2c device */
ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
- if (ret != len) {
- if (ret < 0) {
- em28xx_warn("reading from i2c device at 0x%x failed "
- "(error=%i)\n", addr, ret);
- return ret;
- } else {
- em28xx_warn("%i bytes requested from i2c device at "
- "0x%x, but %i bytes received\n",
- len, addr, ret);
- return -EIO;
- }
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
}
+ /*
+ * NOTE: some devices with two i2c busses have the bad habit to return 0
+ * bytes if we are on bus B AND there was no write attempt to the
+ * specified slave address before AND no device is present at the
+ * requested slave address.
+ * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * spamming the system log on device probing and do nothing here.
+ */
/* Check success of the i2c operation */
ret = dev->em28xx_read_reg(dev, 0x05);
if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from "
- "bridge (error=%i)\n", ret);
+ em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ ret);
return ret;
}
if (ret > 0) {
@@ -282,77 +280,254 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
}
/*
+ * em25xx_bus_B_send_bytes
+ * write bytes to the i2c device
+ */
+static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
+ u16 len)
+{
+ int ret;
+
+ if (len < 1 || len > 64)
+ return -EOPNOTSUPP;
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
+
+ /* Set register and write value */
+ ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len);
+ if (ret != len) {
+ if (ret < 0) {
+ em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ } else {
+ em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
+ len, addr, ret);
+ return -EIO;
+ }
+ }
+ /* Check success */
+ ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
+ /*
+ * NOTE: the only error we've seen so far is
+ * 0x01 when the slave device is not present
+ */
+ if (!ret)
+ return len;
+ else if (ret > 0)
+ return -ENODEV;
+
+ return ret;
+ /*
+ * NOTE: With chip types (other chip IDs) which actually don't support
+ * this operation, it seems to succeed ALWAYS ! (even if there is no
+ * slave device or even no second i2c bus provided)
+ */
+}
+
+/*
+ * em25xx_bus_B_recv_bytes
+ * read bytes from the i2c device
+ */
+static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
+ u16 len)
+{
+ int ret;
+
+ if (len < 1 || len > 64)
+ return -EOPNOTSUPP;
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
+
+ /* Read value */
+ ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ }
+ /*
+ * NOTE: some devices with two i2c busses have the bad habit to return 0
+ * bytes if we are on bus B AND there was no write attempt to the
+ * specified slave address before AND no device is present at the
+ * requested slave address.
+ * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * spamming the system log on device probing and do nothing here.
+ */
+
+ /* Check success */
+ ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
+ /*
+ * NOTE: the only error we've seen so far is
+ * 0x01 when the slave device is not present
+ */
+ if (!ret)
+ return len;
+ else if (ret > 0)
+ return -ENODEV;
+
+ return ret;
+ /*
+ * NOTE: With chip types (other chip IDs) which actually don't support
+ * this operation, it seems to succeed ALWAYS ! (even if there is no
+ * slave device or even no second i2c bus provided)
+ */
+}
+
+/*
+ * em25xx_bus_B_check_for_device()
+ * check if there is a i2c device at the supplied address
+ */
+static int em25xx_bus_B_check_for_device(struct em28xx *dev, u16 addr)
+{
+ u8 buf;
+ int ret;
+
+ ret = em25xx_bus_B_recv_bytes(dev, addr, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ /*
+ * NOTE: With chips which do not support this operation,
+ * it seems to succeed ALWAYS ! (even if no device connected)
+ */
+}
+
+static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
+{
+ struct em28xx *dev = i2c_bus->dev;
+ int rc = -EOPNOTSUPP;
+
+ if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
+ rc = em28xx_i2c_check_for_device(dev, addr);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
+ rc = em2800_i2c_check_for_device(dev, addr);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
+ rc = em25xx_bus_B_check_for_device(dev, addr);
+ if (rc == -ENODEV) {
+ if (i2c_debug)
+ printk(" no device\n");
+ }
+ return rc;
+}
+
+static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
+ struct i2c_msg msg)
+{
+ struct em28xx *dev = i2c_bus->dev;
+ u16 addr = msg.addr << 1;
+ int byte, rc = -EOPNOTSUPP;
+
+ if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
+ rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
+ rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
+ rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
+ if (i2c_debug) {
+ for (byte = 0; byte < msg.len; byte++)
+ printk(" %02x", msg.buf[byte]);
+ }
+ return rc;
+}
+
+static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
+ struct i2c_msg msg, int stop)
+{
+ struct em28xx *dev = i2c_bus->dev;
+ u16 addr = msg.addr << 1;
+ int byte, rc = -EOPNOTSUPP;
+
+ if (i2c_debug) {
+ for (byte = 0; byte < msg.len; byte++)
+ printk(" %02x", msg.buf[byte]);
+ }
+ if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
+ rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
+ rc = em2800_i2c_send_bytes(dev, addr, msg.buf, msg.len);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
+ rc = em25xx_bus_B_send_bytes(dev, addr, msg.buf, msg.len);
+ return rc;
+}
+
+/*
* em28xx_i2c_xfer()
* the main i2c transfer function
*/
static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
- struct em28xx *dev = i2c_adap->algo_data;
- int addr, rc, i, byte;
+ struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
+ struct em28xx *dev = i2c_bus->dev;
+ unsigned bus = i2c_bus->bus;
+ int addr, rc, i;
+ u8 reg;
+
+ rc = rt_mutex_trylock(&dev->i2c_bus_lock);
+ if (rc < 0)
+ return rc;
+
+ /* Switch I2C bus if needed */
+ if (bus != dev->cur_i2c_bus &&
+ i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) {
+ if (bus == 1)
+ reg = EM2874_I2C_SECONDARY_BUS_SELECT;
+ else
+ reg = 0;
+ em28xx_write_reg_bits(dev, EM28XX_R06_I2C_CLK, reg,
+ EM2874_I2C_SECONDARY_BUS_SELECT);
+ dev->cur_i2c_bus = bus;
+ }
- if (num <= 0)
+ if (num <= 0) {
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return 0;
+ }
for (i = 0; i < num; i++) {
addr = msgs[i].addr << 1;
- dprintk2(2, "%s %s addr=%x len=%d:",
- (msgs[i].flags & I2C_M_RD) ? "read" : "write",
- i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+ if (i2c_debug)
+ printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
+ dev->name, __func__ ,
+ (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+ i == num - 1 ? "stop" : "nonstop",
+ addr, msgs[i].len);
if (!msgs[i].len) { /* no len: check only for device presence */
- if (dev->board.is_em2800)
- rc = em2800_i2c_check_for_device(dev, addr);
- else
- rc = em28xx_i2c_check_for_device(dev, addr);
+ rc = i2c_check_for_device(i2c_bus, addr);
if (rc == -ENODEV) {
- if (i2c_debug >= 2)
- printk(" no device\n");
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
} else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
- if (dev->board.is_em2800)
- rc = em2800_i2c_recv_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len);
- else
- rc = em28xx_i2c_recv_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len);
- if (i2c_debug >= 2) {
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(" %02x", msgs[i].buf[byte]);
- }
+ rc = i2c_recv_bytes(i2c_bus, msgs[i]);
} else {
/* write bytes */
- if (i2c_debug >= 2) {
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(" %02x", msgs[i].buf[byte]);
- }
- if (dev->board.is_em2800)
- rc = em2800_i2c_send_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len);
- else
- rc = em28xx_i2c_send_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len,
- i == num - 1);
+ rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
}
if (rc < 0) {
- if (i2c_debug >= 2)
+ if (i2c_debug)
printk(" ERROR: %i\n", rc);
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
- if (i2c_debug >= 2)
+ if (i2c_debug)
printk("\n");
}
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return num;
}
-/* based on linux/sunrpc/svcauth.h and linux/hash.h
+/*
+ * based on linux/sunrpc/svcauth.h and linux/hash.h
* The original hash function returns a different value, if arch is x86_64
- * or i386.
+ * or i386.
*/
static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
{
@@ -375,127 +550,230 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
return (hash >> (32 - bits)) & 0xffffffffUL;
}
-static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+/*
+ * Helper function to read data blocks from i2c clients with 8 or 16 bit
+ * address width, 8 bit register width and auto incrementation been activated
+ */
+static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr,
+ bool addr_w16, u16 len, u8 *data)
{
- unsigned char buf, *p = eedata;
- struct em28xx_eeprom *em_eeprom = (void *)eedata;
- int i, err, size = len, block, block_max;
-
- if (dev->chip_id == CHIP_ID_EM2874 ||
- dev->chip_id == CHIP_ID_EM28174 ||
- dev->chip_id == CHIP_ID_EM2884) {
- /* Empia switched to a 16-bit addressable eeprom in newer
- devices. While we could certainly write a routine to read
- the eeprom, there is nothing of use in there that cannot be
- accessed through registers, and there is the risk that we
- could corrupt the eeprom (since a 16-bit read call is
- interpreted as a write call by 8-bit eeproms).
- */
- return 0;
+ int remain = len, rsize, rsize_max, ret;
+ u8 buf[2];
+
+ /* Sanity check */
+ if (addr + remain > (addr_w16 * 0xff00 + 0xff + 1))
+ return -EINVAL;
+ /* Select address */
+ buf[0] = addr >> 8;
+ buf[1] = addr & 0xff;
+ ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16);
+ if (ret < 0)
+ return ret;
+ /* Read data */
+ if (dev->board.is_em2800)
+ rsize_max = 4;
+ else
+ rsize_max = 64;
+ while (remain > 0) {
+ if (remain > rsize_max)
+ rsize = rsize_max;
+ else
+ rsize = remain;
+
+ ret = i2c_master_recv(&dev->i2c_client[bus], data, rsize);
+ if (ret < 0)
+ return ret;
+
+ remain -= rsize;
+ data += rsize;
}
- dev->i2c_client.addr = 0xa0 >> 1;
+ return len;
+}
+
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
+ u8 **eedata, u16 *eedata_len)
+{
+ const u16 len = 256;
+ /*
+ * FIXME common length/size for bytes to read, to display, hash
+ * calculation and returned device dataset. Simplifies the code a lot,
+ * but we might have to deal with multiple sizes in the future !
+ */
+ int i, err;
+ struct em28xx_eeprom *dev_config;
+ u8 buf, *data;
+
+ *eedata = NULL;
+ *eedata_len = 0;
+
+ /* EEPROM is always on i2c bus 0 on all known devices. */
+
+ dev->i2c_client[bus].addr = 0xa0 >> 1;
/* Check if board has eeprom */
- err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
if (err < 0) {
- em28xx_errdev("board has no eeprom\n");
- memset(eedata, 0, len);
+ em28xx_info("board has no eeprom\n");
return -ENODEV;
}
- buf = 0;
-
- err = i2c_master_send(&dev->i2c_client, &buf, 1);
- if (err != 1) {
- printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
- dev->name, err);
- return err;
+ data = kzalloc(len, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ /* Read EEPROM content */
+ err = em28xx_i2c_read_block(dev, bus, 0x0000,
+ dev->eeprom_addrwidth_16bit,
+ len, data);
+ if (err != len) {
+ em28xx_errdev("failed to read eeprom (err=%d)\n", err);
+ goto error;
}
- if (dev->board.is_em2800)
- block_max = 4;
- else
- block_max = 64;
-
- while (size > 0) {
- if (size > block_max)
- block = block_max;
- else
- block = size;
-
- if (block !=
- (err = i2c_master_recv(&dev->i2c_client, p, block))) {
- printk(KERN_WARNING
- "%s: i2c eeprom read error (err=%d)\n",
- dev->name, err);
- return err;
- }
- size -= block;
- p += block;
- }
+ /* Display eeprom content */
for (i = 0; i < len; i++) {
- if (0 == (i % 16))
- printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
- printk(" %02x", eedata[i]);
+ if (0 == (i % 16)) {
+ if (dev->eeprom_addrwidth_16bit)
+ em28xx_info("i2c eeprom %04x:", i);
+ else
+ em28xx_info("i2c eeprom %02x:", i);
+ }
+ printk(" %02x", data[i]);
if (15 == (i % 16))
printk("\n");
}
+ if (dev->eeprom_addrwidth_16bit)
+ em28xx_info("i2c eeprom %04x: ... (skipped)\n", i);
+
+ if (dev->eeprom_addrwidth_16bit &&
+ data[0] == 0x26 && data[3] == 0x00) {
+ /* new eeprom format; size 4-64kb */
+ u16 mc_start;
+ u16 hwconf_offset;
+
+ dev->hash = em28xx_hash_mem(data, len, 32);
+ mc_start = (data[1] << 8) + 4; /* usually 0x0004 */
+
+ em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
+ data[0], data[1], data[2], data[3], dev->hash);
+ em28xx_info("EEPROM info:\n");
+ em28xx_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n",
+ mc_start, data[2]);
+ /*
+ * boot configuration (address 0x0002):
+ * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz
+ * [1] always selects 12 kb RAM
+ * [2] USB device speed: 1 = force Full Speed; 0 = auto detect
+ * [4] 1 = force fast mode and no suspend for device testing
+ * [5:7] USB PHY tuning registers; determined by device
+ * characterization
+ */
+
+ /*
+ * Read hardware config dataset offset from address
+ * (microcode start + 46)
+ */
+ err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2,
+ data);
+ if (err != 2) {
+ em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
+ err);
+ goto error;
+ }
- if (em_eeprom->id == 0x9567eb1a)
- dev->hash = em28xx_hash_mem(eedata, len, 32);
+ /* Calculate hardware config dataset start address */
+ hwconf_offset = mc_start + data[0] + (data[1] << 8);
+
+ /* Read hardware config dataset */
+ /*
+ * NOTE: the microcode copy can be multiple pages long, but
+ * we assume the hardware config dataset is the same as in
+ * the old eeprom and not longer than 256 bytes.
+ * tveeprom is currently also limited to 256 bytes.
+ */
+ err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len,
+ data);
+ if (err != len) {
+ em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
+ err);
+ goto error;
+ }
- printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
- dev->name, em_eeprom->id, dev->hash);
+ /* Verify hardware config dataset */
+ /* NOTE: not all devices provide this type of dataset */
+ if (data[0] != 0x1a || data[1] != 0xeb ||
+ data[2] != 0x67 || data[3] != 0x95) {
+ em28xx_info("\tno hardware configuration dataset found in eeprom\n");
+ kfree(data);
+ return 0;
+ }
- printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
+ /* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */
+
+ } else if (!dev->eeprom_addrwidth_16bit &&
+ data[0] == 0x1a && data[1] == 0xeb &&
+ data[2] == 0x67 && data[3] == 0x95) {
+ dev->hash = em28xx_hash_mem(data, len, 32);
+ em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
+ data[0], data[1], data[2], data[3], dev->hash);
+ em28xx_info("EEPROM info:\n");
+ } else {
+ em28xx_info("unknown eeprom format or eeprom corrupted !\n");
+ err = -ENODEV;
+ goto error;
+ }
- switch (em_eeprom->chip_conf >> 4 & 0x3) {
+ *eedata = data;
+ *eedata_len = len;
+ dev_config = (void *)eedata;
+
+ switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
case 0:
- printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
+ em28xx_info("\tNo audio on board.\n");
break;
case 1:
- printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
- dev->name);
+ em28xx_info("\tAC97 audio (5 sample rates)\n");
break;
case 2:
- printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
- dev->name);
+ em28xx_info("\tI2S audio, sample rate=32k\n");
break;
case 3:
- printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
- dev->name);
+ em28xx_info("\tI2S audio, 3 sample rates\n");
break;
}
- if (em_eeprom->chip_conf & 1 << 3)
- printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
+ if (le16_to_cpu(dev_config->chip_conf) & 1 << 3)
+ em28xx_info("\tUSB Remote wakeup capable\n");
- if (em_eeprom->chip_conf & 1 << 2)
- printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
+ if (le16_to_cpu(dev_config->chip_conf) & 1 << 2)
+ em28xx_info("\tUSB Self power capable\n");
- switch (em_eeprom->chip_conf & 0x3) {
+ switch (le16_to_cpu(dev_config->chip_conf) & 0x3) {
case 0:
- printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
+ em28xx_info("\t500mA max power\n");
break;
case 1:
- printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
+ em28xx_info("\t400mA max power\n");
break;
case 2:
- printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
+ em28xx_info("\t300mA max power\n");
break;
case 3:
- printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
+ em28xx_info("\t200mA max power\n");
break;
}
- printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
- dev->name,
- em_eeprom->string_idx_table,
- em_eeprom->string1,
- em_eeprom->string2,
- em_eeprom->string3);
+ em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+ dev_config->string_idx_table,
+ le16_to_cpu(dev_config->string1),
+ le16_to_cpu(dev_config->string2),
+ le16_to_cpu(dev_config->string3));
return 0;
+
+error:
+ kfree(data);
+ return err;
}
/* ----------------------------------------------------------- */
@@ -503,13 +781,20 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
/*
* functionality()
*/
-static u32 functionality(struct i2c_adapter *adap)
+static u32 functionality(struct i2c_adapter *i2c_adap)
{
- struct em28xx *dev = adap->algo_data;
- u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
- if (dev->board.is_em2800)
- func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
- return func_flags;
+ struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
+
+ if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) ||
+ (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) {
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ } else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) {
+ return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) &
+ ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
+ }
+
+ WARN(1, "Unknown i2c bus algorithm.\n");
+ return 0;
}
static struct i2c_algorithm em28xx_algo = {
@@ -556,7 +841,7 @@ static char *i2c_devs[128] = {
* do_i2c_scan()
* check i2c address range for devices
*/
-void em28xx_do_i2c_scan(struct em28xx *dev)
+void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus)
{
u8 i2c_devicelist[128];
unsigned char buf;
@@ -565,55 +850,68 @@ void em28xx_do_i2c_scan(struct em28xx *dev)
memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
- dev->i2c_client.addr = i;
- rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ dev->i2c_client[bus].addr = i;
+ rc = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
if (rc < 0)
continue;
i2c_devicelist[i] = i;
- printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
- dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ em28xx_info("found i2c device @ 0x%x on bus %d [%s]\n",
+ i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???");
}
- dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
- ARRAY_SIZE(i2c_devicelist), 32);
+ if (bus == dev->def_i2c_bus)
+ dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
+ ARRAY_SIZE(i2c_devicelist), 32);
}
/*
* em28xx_i2c_register()
* register i2c bus
*/
-int em28xx_i2c_register(struct em28xx *dev)
+int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
+ enum em28xx_i2c_algo_type algo_type)
{
int retval;
BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
- dev->i2c_adap = em28xx_adap_template;
- dev->i2c_adap.dev.parent = &dev->udev->dev;
- strcpy(dev->i2c_adap.name, dev->name);
- dev->i2c_adap.algo_data = dev;
- i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
- retval = i2c_add_adapter(&dev->i2c_adap);
+ if (bus >= NUM_I2C_BUSES)
+ return -ENODEV;
+
+ dev->i2c_adap[bus] = em28xx_adap_template;
+ dev->i2c_adap[bus].dev.parent = &dev->udev->dev;
+ strcpy(dev->i2c_adap[bus].name, dev->name);
+
+ dev->i2c_bus[bus].bus = bus;
+ dev->i2c_bus[bus].algo_type = algo_type;
+ dev->i2c_bus[bus].dev = dev;
+ dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus];
+ i2c_set_adapdata(&dev->i2c_adap[bus], &dev->v4l2_dev);
+
+ retval = i2c_add_adapter(&dev->i2c_adap[bus]);
if (retval < 0) {
em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
__func__, retval);
return retval;
}
- dev->i2c_client = em28xx_client_template;
- dev->i2c_client.adapter = &dev->i2c_adap;
+ dev->i2c_client[bus] = em28xx_client_template;
+ dev->i2c_client[bus].adapter = &dev->i2c_adap[bus];
- retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
- if ((retval < 0) && (retval != -ENODEV)) {
- em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
- __func__, retval);
+ /* Up to now, all eeproms are at bus 0 */
+ if (!bus) {
+ retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len);
+ if ((retval < 0) && (retval != -ENODEV)) {
+ em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
+ __func__, retval);
- return retval;
+ return retval;
+ }
}
if (i2c_scan)
- em28xx_do_i2c_scan(dev);
+ em28xx_do_i2c_scan(dev, bus);
return 0;
}
@@ -622,8 +920,11 @@ int em28xx_i2c_register(struct em28xx *dev)
* em28xx_i2c_unregister()
* unregister i2c_bus
*/
-int em28xx_i2c_unregister(struct em28xx *dev)
+int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus)
{
- i2c_del_adapter(&dev->i2c_adap);
+ if (bus >= NUM_I2C_BUSES)
+ return -ENODEV;
+
+ i2c_del_adapter(&dev->i2c_adap[bus]);
return 0;
}
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 1bef990b3f1..466b19d0d76 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -280,11 +280,12 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
{
+ struct em28xx *dev = ir->dev;
static u32 ir_key;
int rc;
struct i2c_client client;
- client.adapter = &ir->dev->i2c_adap;
+ client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
client.addr = ir->i2c_dev_addr;
rc = ir->get_key_i2c(&client, &ir_key);
@@ -461,7 +462,7 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev)
};
while (addr_list[i] != I2C_CLIENT_END) {
- if (i2c_probe_func_quick_read(&dev->i2c_adap, addr_list[i]) == 1)
+ if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], addr_list[i]) == 1)
return addr_list[i];
i++;
}
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 885089e22bc..622871db04a 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -48,7 +48,7 @@
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03
- /* GPIO/GPO registers */
+/* GPIO/GPO registers */
#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
@@ -120,12 +120,23 @@
#define EM28XX_R1E_CWIDTH 0x1e
#define EM28XX_R1F_CHEIGHT 0x1f
-#define EM28XX_R20_YGAIN 0x20
-#define EM28XX_R21_YOFFSET 0x21
-#define EM28XX_R22_UVGAIN 0x22
-#define EM28XX_R23_UOFFSET 0x23
-#define EM28XX_R24_VOFFSET 0x24
-#define EM28XX_R25_SHARPNESS 0x25
+#define EM28XX_R20_YGAIN 0x20 /* contrast [0:4] */
+#define CONTRAST_DEFAULT 0x10
+
+#define EM28XX_R21_YOFFSET 0x21 /* brightness */ /* signed */
+#define BRIGHTNESS_DEFAULT 0x00
+
+#define EM28XX_R22_UVGAIN 0x22 /* saturation [0:4] */
+#define SATURATION_DEFAULT 0x10
+
+#define EM28XX_R23_UOFFSET 0x23 /* blue balance */ /* signed */
+#define BLUE_BALANCE_DEFAULT 0x00
+
+#define EM28XX_R24_VOFFSET 0x24 /* red balance */ /* signed */
+#define RED_BALANCE_DEFAULT 0x00
+
+#define EM28XX_R25_SHARPNESS 0x25 /* sharpness [0:4] */
+#define SHARPNESS_DEFAULT 0x00
#define EM28XX_R26_COMPR 0x26
#define EM28XX_R27_OUTFMT 0x27
@@ -152,8 +163,17 @@
#define EM28XX_R31_HSCALEHIGH 0x31
#define EM28XX_R32_VSCALELOW 0x32
#define EM28XX_R33_VSCALEHIGH 0x33
+#define EM28XX_HVSCALE_MAX 0x3fff /* => 20% */
+
#define EM28XX_R34_VBI_START_H 0x34
#define EM28XX_R35_VBI_START_V 0x35
+/*
+ * NOTE: the EM276x (and EM25xx, EM277x/8x ?) (camera bridges) use these
+ * registers for a different unknown purpose.
+ * => register 0x34 is set to capture width / 16
+ * => register 0x35 is set to capture height / 16
+ */
+
#define EM28XX_R36_VBI_WIDTH 0x36
#define EM28XX_R37_VBI_HEIGHT 0x37
@@ -206,6 +226,7 @@ enum em28xx_chip_id {
CHIP_ID_EM2860 = 34,
CHIP_ID_EM2870 = 35,
CHIP_ID_EM2883 = 36,
+ CHIP_ID_EM2765 = 54,
CHIP_ID_EM2874 = 65,
CHIP_ID_EM2884 = 68,
CHIP_ID_EM28174 = 113,
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 32bd7de5dec..32d60e5546b 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -52,7 +52,7 @@
#define DRIVER_DESC "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION "0.1.3"
+#define EM28XX_VERSION "0.2.0"
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
@@ -76,6 +76,16 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(EM28XX_VERSION);
+
+#define EM25XX_FRMDATAHDR_BYTE1 0x02
+#define EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE 0x20
+#define EM25XX_FRMDATAHDR_BYTE2_FRAME_END 0x02
+#define EM25XX_FRMDATAHDR_BYTE2_FRAME_ID 0x01
+#define EM25XX_FRMDATAHDR_BYTE2_MASK (EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE | \
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_END | \
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_ID)
+
+
static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
@@ -408,6 +418,62 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
em28xx_copy_video(dev, buf, data_pkt, data_len);
}
+/*
+ * Process data packet according to the em25xx/em276x/7x/8x frame data format
+ */
+static inline void process_frame_data_em25xx(struct em28xx *dev,
+ unsigned char *data_pkt,
+ unsigned int data_len)
+{
+ struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
+ struct em28xx_dmaqueue *dmaq = &dev->vidq;
+ bool frame_end = 0;
+
+ /* Check for header */
+ /* NOTE: at least with bulk transfers, only the first packet
+ * has a header and has always set the FRAME_END bit */
+ if (data_len >= 2) { /* em25xx header is only 2 bytes long */
+ if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) &&
+ ((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) {
+ dev->top_field = !(data_pkt[1] &
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_ID);
+ frame_end = data_pkt[1] &
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_END;
+ data_pkt += 2;
+ data_len -= 2;
+ }
+
+ /* Finish field and prepare next (BULK only) */
+ if (dev->analog_xfer_bulk && frame_end) {
+ buf = finish_field_prepare_next(dev, buf, dmaq);
+ dev->usb_ctl.vid_buf = buf;
+ }
+ /* NOTE: in ISOC mode when a new frame starts and buf==NULL,
+ * we COULD already prepare a buffer here to avoid skipping the
+ * first frame.
+ */
+ }
+
+ /* Copy data */
+ if (buf != NULL && data_len > 0)
+ em28xx_copy_video(dev, buf, data_pkt, data_len);
+
+ /* Finish frame (ISOC only) => avoids lag of 1 frame */
+ if (!dev->analog_xfer_bulk && frame_end) {
+ buf = finish_field_prepare_next(dev, buf, dmaq);
+ dev->usb_ctl.vid_buf = buf;
+ }
+
+ /* NOTE: Tested with USB bulk transfers only !
+ * The wording in the datasheet suggests that isoc might work different.
+ * The current code assumes that with isoc transfers each packet has a
+ * header like with the other em28xx devices.
+ */
+ /* NOTE: Support for interlaced mode is pure theory. It has not been
+ * tested and it is unknown if these devices actually support it. */
+ /* NOTE: No VBI support yet (these chips likely do not support VBI). */
+}
+
/* Processes and copies the URB data content (video and VBI data) */
static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
{
@@ -460,7 +526,13 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
continue;
}
- process_frame_data_em28xx(dev, usb_data_pkt, usb_data_len);
+ if (dev->is_em25xx)
+ process_frame_data_em25xx(dev,
+ usb_data_pkt, usb_data_len);
+ else
+ process_frame_data_em28xx(dev,
+ usb_data_pkt, usb_data_len);
+
}
return 1;
}
@@ -700,6 +772,7 @@ int em28xx_vb2_setup(struct em28xx *dev)
q = &dev->vb_vidq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_video_qops;
@@ -713,6 +786,7 @@ int em28xx_vb2_setup(struct em28xx *dev)
q = &dev->vb_vbiq;
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_vbi_qops;
@@ -782,33 +856,45 @@ void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
+ int ret = -EINVAL;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
dev->mute = ctrl->val;
+ ret = em28xx_audio_analog_set(dev);
break;
case V4L2_CID_AUDIO_VOLUME:
dev->volume = ctrl->val;
+ ret = em28xx_audio_analog_set(dev);
+ break;
+ case V4L2_CID_CONTRAST:
+ ret = em28xx_write_reg(dev, EM28XX_R20_YGAIN, ctrl->val);
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ ret = em28xx_write_reg(dev, EM28XX_R21_YOFFSET, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ ret = em28xx_write_reg(dev, EM28XX_R22_UVGAIN, ctrl->val);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = em28xx_write_reg(dev, EM28XX_R23_UOFFSET, ctrl->val);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ret = em28xx_write_reg(dev, EM28XX_R24_VOFFSET, ctrl->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ ret = em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, ctrl->val);
break;
}
- return em28xx_audio_analog_set(dev);
+ return (ret < 0) ? ret : 0;
}
const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
.s_ctrl = em28xx_s_ctrl,
};
-static int check_dev(struct em28xx *dev)
-{
- if (dev->disconnected) {
- em28xx_errdev("v4l2 ioctl: device not present\n");
- return -ENODEV;
- }
- return 0;
-}
-
-static void get_scale(struct em28xx *dev,
+static void size_to_scale(struct em28xx *dev,
unsigned int width, unsigned int height,
unsigned int *hscale, unsigned int *vscale)
{
@@ -816,12 +902,23 @@ static void get_scale(struct em28xx *dev,
unsigned int maxh = norm_maxh(dev);
*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
- if (*hscale >= 0x4000)
- *hscale = 0x3fff;
+ if (*hscale > EM28XX_HVSCALE_MAX)
+ *hscale = EM28XX_HVSCALE_MAX;
*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
- if (*vscale >= 0x4000)
- *vscale = 0x3fff;
+ if (*vscale > EM28XX_HVSCALE_MAX)
+ *vscale = EM28XX_HVSCALE_MAX;
+}
+
+static void scale_to_size(struct em28xx *dev,
+ unsigned int hscale, unsigned int vscale,
+ unsigned int *width, unsigned int *height)
+{
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+
+ *width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+ *height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
}
/* ------------------------------------------------------------------
@@ -898,10 +995,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
1, 0);
}
- get_scale(dev, width, height, &hscale, &vscale);
-
- width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
- height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+ size_to_scale(dev, width, height, &hscale, &vscale);
+ scale_to_size(dev, hscale, vscale, &width, &height);
f->fmt.pix.width = width;
f->fmt.pix.height = height;
@@ -932,7 +1027,7 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
dev->height = height;
/* set new image size */
- get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_resolution_set(dev);
@@ -957,13 +1052,6 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- if (dev->board.is_webcam)
- return -ENOTTY;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
*norm = dev->norm;
@@ -974,48 +1062,35 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- if (dev->board.is_webcam)
- return -ENOTTY;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
struct v4l2_format f;
- int rc;
- if (dev->board.is_webcam)
- return -ENOTTY;
- if (*norm == dev->norm)
+ if (norm == dev->norm)
return 0;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (dev->streaming_users > 0)
return -EBUSY;
- dev->norm = *norm;
+ dev->norm = norm;
/* Adjusts width/height, if needed */
f.fmt.pix.width = 720;
- f.fmt.pix.height = (*norm & V4L2_STD_525_60) ? 480 : 576;
+ f.fmt.pix.height = (norm & V4L2_STD_525_60) ? 480 : 576;
vidioc_try_fmt_vid_cap(file, priv, &f);
/* set new image size */
dev->width = f.fmt.pix.width;
dev->height = f.fmt.pix.height;
- get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_resolution_set(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
@@ -1030,9 +1105,6 @@ static int vidioc_g_parm(struct file *file, void *priv,
struct em28xx *dev = fh->dev;
int rc = 0;
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
if (dev->board.is_webcam)
rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
@@ -1050,12 +1122,6 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- if (!dev->board.is_webcam)
- return -ENOTTY;
-
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
}
@@ -1116,11 +1182,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (i >= MAX_EM28XX_INPUT)
return -EINVAL;
@@ -1136,9 +1197,6 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- if (!dev->audio_mode.has_audio)
- return -EINVAL;
-
switch (a->index) {
case EM28XX_AMUX_VIDEO:
strcpy(a->name, "Television");
@@ -1179,10 +1237,6 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
-
- if (!dev->audio_mode.has_audio)
- return -EINVAL;
-
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
if (0 == INPUT(a->index)->type)
@@ -1202,11 +1256,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (0 != t->index)
return -EINVAL;
@@ -1218,15 +1267,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (0 != t->index)
return -EINVAL;
@@ -1249,39 +1293,22 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
+ struct v4l2_frequency new_freq = *f;
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (0 != f->tuner)
return -EINVAL;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
- dev->ctl_freq = f->frequency;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+ dev->ctl_freq = new_freq.frequency;
return 0;
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int em28xx_reg_len(int reg)
-{
- switch (reg) {
- case EM28XX_R40_AC97LSB:
- case EM28XX_R30_HSCALELOW:
- case EM28XX_R32_VSCALELOW:
- return 2;
- default:
- return 1;
- }
-}
-
static int vidioc_g_chip_ident(struct file *file, void *priv,
struct v4l2_dbg_chip_ident *chip)
{
@@ -1290,9 +1317,9 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(&chip->match))
- chip->ident = V4L2_IDENT_NONE;
+ if (chip->match.type == V4L2_CHIP_MATCH_BRIDGE) {
+ if (chip->match.addr > 1)
+ return -EINVAL;
return 0;
}
if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
@@ -1304,6 +1331,33 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_chip_info(struct file *file, void *priv,
+ struct v4l2_dbg_chip_info *chip)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ if (chip->match.addr > 1)
+ return -EINVAL;
+ if (chip->match.addr == 1)
+ strlcpy(chip->name, "ac97", sizeof(chip->name));
+ else
+ strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
+ return 0;
+}
+
+static int em28xx_reg_len(int reg)
+{
+ switch (reg) {
+ case EM28XX_R40_AC97LSB:
+ case EM28XX_R30_HSCALELOW:
+ case EM28XX_R32_VSCALELOW:
+ return 2;
+ default:
+ return 1;
+ }
+}
static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -1313,6 +1367,12 @@ static int vidioc_g_register(struct file *file, void *priv,
int ret;
switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_BRIDGE:
+ if (reg->match.addr > 1)
+ return -EINVAL;
+ if (!reg->match.addr)
+ break;
+ /* fall-through */
case V4L2_CHIP_MATCH_AC97:
ret = em28xx_read_ac97(dev, reg->reg);
if (ret < 0)
@@ -1329,8 +1389,7 @@ static int vidioc_g_register(struct file *file, void *priv,
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
return 0;
default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
+ return -EINVAL;
}
/* Match host */
@@ -1356,13 +1415,19 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
__le16 buf;
switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_BRIDGE:
+ if (reg->match.addr > 1)
+ return -EINVAL;
+ if (!reg->match.addr)
+ break;
+ /* fall-through */
case V4L2_CHIP_MATCH_AC97:
return em28xx_write_ac97(dev, reg->reg, reg->val);
case V4L2_CHIP_MATCH_I2C_DRIVER:
@@ -1373,8 +1438,7 @@ static int vidioc_s_register(struct file *file, void *priv,
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
return 0;
default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
+ return -EINVAL;
}
/* Match host */
@@ -1386,26 +1450,6 @@ static int vidioc_s_register(struct file *file, void *priv,
#endif
-static int vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cc)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- cc->bounds.left = 0;
- cc->bounds.top = 0;
- cc->bounds.width = dev->width;
- cc->bounds.height = dev->height;
- cc->defrect = cc->bounds;
- cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
- cc->pixelaspect.denominator = 59;
-
- return 0;
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -1482,8 +1526,12 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
/* Report a continuous range */
fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
- fsize->stepwise.min_width = 48;
- fsize->stepwise.min_height = 32;
+ scale_to_size(dev, EM28XX_HVSCALE_MAX, EM28XX_HVSCALE_MAX,
+ &fsize->stepwise.min_width, &fsize->stepwise.min_height);
+ if (fsize->stepwise.min_width < 48)
+ fsize->stepwise.min_width = 48;
+ if (fsize->stepwise.min_height < 38)
+ fsize->stepwise.min_height = 38;
fsize->stepwise.max_width = maxw;
fsize->stepwise.max_height = maxh;
fsize->stepwise.step_width = 1;
@@ -1522,35 +1570,6 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *format)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- format->fmt.vbi.samples_per_line = dev->vbi_width;
- format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- format->fmt.vbi.offset = 0;
- format->fmt.vbi.flags = 0;
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
- format->fmt.vbi.count[0] = dev->vbi_height;
- format->fmt.vbi.count[1] = dev->vbi_height;
- memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
-
- /* Varies by video standard (NTSC, PAL, etc.) */
- if (dev->norm & V4L2_STD_525_60) {
- /* NTSC */
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
- } else if (dev->norm & V4L2_STD_625_50) {
- /* PAL */
- format->fmt.vbi.start[0] = 6;
- format->fmt.vbi.start[1] = 318;
- }
-
- return 0;
-}
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
@@ -1564,7 +1583,6 @@ static int radio_g_tuner(struct file *file, void *priv,
return -EINVAL;
strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
@@ -1572,7 +1590,7 @@ static int radio_g_tuner(struct file *file, void *priv,
}
static int radio_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
@@ -1749,11 +1767,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
- .vidioc_cropcap = vidioc_cropcap,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
@@ -1778,10 +1795,11 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = vidioc_g_chip_info,
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#endif
};
@@ -1808,7 +1826,9 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = vidioc_g_chip_info,
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
@@ -1887,9 +1907,42 @@ int em28xx_register_analog_devices(struct em28xx *dev)
(EM28XX_XCLK_AUDIO_UNMUTE | val));
em28xx_set_outfmt(dev);
- em28xx_colorlevels_set_default(dev);
em28xx_compression_disable(dev);
+ /* Add image controls */
+ /* NOTE: at this point, the subdevices are already registered, so bridge
+ * controls are only added/enabled when no subdevice provides them */
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_CONTRAST))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_CONTRAST,
+ 0, 0x1f, 1, CONTRAST_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BRIGHTNESS))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_BRIGHTNESS,
+ -0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SATURATION))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_SATURATION,
+ 0, 0x1f, 1, SATURATION_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BLUE_BALANCE))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE,
+ -0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RED_BALANCE))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_RED_BALANCE,
+ -0x30, 0x30, 1, RED_BALANCE_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SHARPNESS))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_SHARPNESS,
+ 0, 0x0f, 1, SHARPNESS_DEFAULT);
+
+ /* Reset image controls */
+ em28xx_colorlevels_set_default(dev);
+ v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+ if (dev->ctrl_handler.error)
+ return dev->ctrl_handler.error;
+
/* allocate and fill video video_device struct */
dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
if (!dev->vdev) {
@@ -1899,6 +1952,25 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->vdev->queue = &dev->vb_vidq;
dev->vdev->queue->lock = &dev->vb_queue_lock;
+ /* disable inapplicable ioctls */
+ if (dev->board.is_webcam) {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_QUERYSTD);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD);
+ } else {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ }
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_FREQUENCY);
+ }
+ if (!dev->audio_mode.has_audio) {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_AUDIO);
+ }
+
/* register v4l2 video video_device */
ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
@@ -1916,6 +1988,19 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->vbi_dev->queue = &dev->vb_vbiq;
dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
+ /* disable inapplicable ioctls */
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_FREQUENCY);
+ }
+ if (!dev->audio_mode.has_audio) {
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_AUDIO);
+ }
+
/* register v4l2 vbi video_device */
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 5f0b2c59e84..a9323b63d8e 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -42,28 +42,28 @@
#include "em28xx-reg.h"
/* Boards supported by driver */
-#define EM2800_BOARD_UNKNOWN 0
-#define EM2820_BOARD_UNKNOWN 1
-#define EM2820_BOARD_TERRATEC_CINERGY_250 2
-#define EM2820_BOARD_PINNACLE_USB_2 3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
-#define EM2820_BOARD_MSI_VOX_USB_2 5
-#define EM2800_BOARD_TERRATEC_CINERGY_200 6
-#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
-#define EM2800_BOARD_KWORLD_USB2800 8
-#define EM2820_BOARD_PINNACLE_DVC_90 9
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
-#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
-#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
-#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
-#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
-#define EM2800_BOARD_VGEAR_POCKETTV 15
-#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16
-#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18
-#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19
-#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20
-#define EM2800_BOARD_GRABBEEX_USB2800 21
+#define EM2800_BOARD_UNKNOWN 0
+#define EM2820_BOARD_UNKNOWN 1
+#define EM2820_BOARD_TERRATEC_CINERGY_250 2
+#define EM2820_BOARD_PINNACLE_USB_2 3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
+#define EM2820_BOARD_MSI_VOX_USB_2 5
+#define EM2800_BOARD_TERRATEC_CINERGY_200 6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
+#define EM2800_BOARD_KWORLD_USB2800 8
+#define EM2820_BOARD_PINNACLE_DVC_90 9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
+#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
+#define EM2800_BOARD_VGEAR_POCKETTV 15
+#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16
+#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18
+#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19
+#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20
+#define EM2800_BOARD_GRABBEEX_USB2800 21
#define EM2750_BOARD_UNKNOWN 22
#define EM2750_BOARD_DLCW_130 23
#define EM2820_BOARD_DLINK_USB_TV 24
@@ -99,36 +99,37 @@
#define EM2882_BOARD_KWORLD_VS_DVBT 54
#define EM2882_BOARD_TERRATEC_HYBRID_XS 55
#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56
-#define EM2883_BOARD_KWORLD_HYBRID_330U 57
+#define EM2883_BOARD_KWORLD_HYBRID_330U 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61
#define EM2820_BOARD_GADMEI_TVR200 62
-#define EM2860_BOARD_KAIOMY_TVNPC_U2 63
-#define EM2860_BOARD_EASYCAP 64
+#define EM2860_BOARD_KAIOMY_TVNPC_U2 63
+#define EM2860_BOARD_EASYCAP 64
#define EM2820_BOARD_IODATA_GVMVP_SZ 65
#define EM2880_BOARD_EMPIRE_DUAL_TV 66
#define EM2860_BOARD_TERRATEC_GRABBY 67
#define EM2860_BOARD_TERRATEC_AV350 68
#define EM2882_BOARD_KWORLD_ATSC_315U 69
#define EM2882_BOARD_EVGA_INDTUBE 70
-#define EM2820_BOARD_SILVERCREST_WEBCAM 71
-#define EM2861_BOARD_GADMEI_UTV330PLUS 72
-#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
+#define EM2820_BOARD_SILVERCREST_WEBCAM 71
+#define EM2861_BOARD_GADMEI_UTV330PLUS 72
+#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
#define EM2800_BOARD_VC211A 74
#define EM2882_BOARD_DIKOM_DK300 75
#define EM2870_BOARD_KWORLD_A340 76
#define EM2874_BOARD_LEADERSHIP_ISDBT 77
-#define EM28174_BOARD_PCTV_290E 78
+#define EM28174_BOARD_PCTV_290E 78
#define EM2884_BOARD_TERRATEC_H5 79
-#define EM28174_BOARD_PCTV_460E 80
+#define EM28174_BOARD_PCTV_460E 80
#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81
#define EM2884_BOARD_CINERGY_HTC_STICK 82
-#define EM2860_BOARD_HT_VIDBOX_NW03 83
-#define EM2874_BOARD_MAXMEDIA_UB425_TC 84
-#define EM2884_BOARD_PCTV_510E 85
-#define EM2884_BOARD_PCTV_520E 86
+#define EM2860_BOARD_HT_VIDBOX_NW03 83
+#define EM2874_BOARD_MAXMEDIA_UB425_TC 84
+#define EM2884_BOARD_PCTV_510E 85
+#define EM2884_BOARD_PCTV_520E 86
#define EM2884_BOARD_TERRATEC_HTC_USB_XS 87
+#define EM2884_BOARD_C3TECH_DIGITAL_DUO 88
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -157,6 +158,9 @@
#define EM28XX_NUM_BUFS 5
#define EM28XX_DVB_NUM_BUFS 5
+/* max number of I2C buses on em28xx devices */
+#define NUM_I2C_BUSES 2
+
/* isoc transfers: number of packets for each buffer
windows requests only 64 packets .. so we better do the same
this is what I found out for all alternate numbers there!
@@ -172,27 +176,6 @@
#define EM28XX_INTERLACED_DEFAULT 1
-/*
-#define (use usbview if you want to get the other alternate number infos)
-#define
-#define alternate number 2
-#define Endpoint Address: 82
- Direction: in
- Attribute: 1
- Type: Isoc
- Max Packet Size: 1448
- Interval: 125us
-
- alternate number 7
-
- Endpoint Address: 82
- Direction: in
- Attribute: 1
- Type: Isoc
- Max Packet Size: 3072
- Interval: 125us
-*/
-
/* time in msecs to wait for i2c writes to finish */
#define EM2800_I2C_XFER_TIMEOUT 20
@@ -381,6 +364,7 @@ enum em28xx_sensor {
EM28XX_MT9V011,
EM28XX_MT9M001,
EM28XX_MT9M111,
+ EM28XX_OV2640,
};
enum em28xx_adecoder {
@@ -393,6 +377,7 @@ struct em28xx_board {
int vchannels;
int tuner_type;
int tuner_addr;
+ unsigned def_i2c_bus; /* Default I2C bus */
/* i2c flags */
unsigned int tda9887_conf;
@@ -426,15 +411,15 @@ struct em28xx_board {
};
struct em28xx_eeprom {
- u32 id; /* 0x9567eb1a */
- u16 vendor_ID;
- u16 product_ID;
+ u8 id[4]; /* 1a eb 67 95 */
+ __le16 vendor_ID;
+ __le16 product_ID;
- u16 chip_conf;
+ __le16 chip_conf;
- u16 board_conf;
+ __le16 board_conf;
- u16 string1, string2, string3;
+ __le16 string1, string2, string3;
u8 string_idx_table;
};
@@ -477,6 +462,20 @@ struct em28xx_fh {
enum v4l2_buf_type type;
};
+enum em28xx_i2c_algo_type {
+ EM28XX_I2C_ALGO_EM28XX = 0,
+ EM28XX_I2C_ALGO_EM2800,
+ EM28XX_I2C_ALGO_EM25XX_BUS_B,
+};
+
+struct em28xx_i2c_bus {
+ struct em28xx *dev;
+
+ unsigned bus;
+ enum em28xx_i2c_algo_type algo_type;
+};
+
+
/* main device struct */
struct em28xx {
/* generic device properties */
@@ -484,6 +483,7 @@ struct em28xx {
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
enum em28xx_chip_id chip_id;
+ unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
unsigned char disconnected:1; /* device has been diconnected */
@@ -491,8 +491,6 @@ struct em28xx {
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
- /* provides ac97 mute and volume overrides */
- struct v4l2_ctrl_handler ac97_ctrl_handler;
struct em28xx_board board;
/* Webcam specific fields */
@@ -511,8 +509,8 @@ struct em28xx {
unsigned int is_audio_only:1;
/* Controls audio streaming */
- struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
- atomic_t stream_started; /* stream should be running if true */
+ struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
+ atomic_t stream_started; /* stream should be running if true */
struct em28xx_fmt *format;
@@ -530,9 +528,17 @@ struct em28xx {
int tuner_type; /* type of the tuner */
int tuner_addr; /* tuner address */
int tda9887_conf;
+
/* i2c i/o */
- struct i2c_adapter i2c_adap;
- struct i2c_client i2c_client;
+ struct i2c_adapter i2c_adap[NUM_I2C_BUSES];
+ struct i2c_client i2c_client[NUM_I2C_BUSES];
+ struct em28xx_i2c_bus i2c_bus[NUM_I2C_BUSES];
+
+ unsigned char eeprom_addrwidth_16bit:1;
+ unsigned def_i2c_bus; /* Default I2C bus */
+ unsigned cur_i2c_bus; /* Current I2C bus */
+ struct rt_mutex i2c_bus_lock;
+
/* video for linux */
int users; /* user count for exclusive use */
int streaming_users; /* Number of actively streaming users */
@@ -584,7 +590,9 @@ struct em28xx {
/* resources in use */
unsigned int resources;
- unsigned char eedata[256];
+ /* eeprom content */
+ u8 *eedata;
+ u16 eedata_len;
/* Isoc control struct */
struct em28xx_dmaqueue vidq;
@@ -600,7 +608,7 @@ struct em28xx {
u8 analog_ep_isoc; /* address of isoc endpoint for analog */
u8 analog_ep_bulk; /* address of bulk endpoint for analog */
u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
- u8 dvb_ep_bulk; /* address of bulk endpoint for DVC */
+ u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */
int alt; /* alternate setting */
int max_pkt_size; /* max packet size of the selected ep at alt */
int packet_multiplier; /* multiplier for wMaxPacketSize, used for
@@ -651,16 +659,12 @@ struct em28xx_ops {
};
/* Provided by em28xx-i2c.c */
-void em28xx_do_i2c_scan(struct em28xx *dev);
-int em28xx_i2c_register(struct em28xx *dev);
-int em28xx_i2c_unregister(struct em28xx *dev);
+void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus);
+int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
+ enum em28xx_i2c_algo_type algo_type);
+int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus);
/* Provided by em28xx-core.c */
-
-u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
-void em28xx_queue_unusedframes(struct em28xx *dev);
-void em28xx_release_buffers(struct em28xx *dev);
-
int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
char *buf, int len);
int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
@@ -693,7 +697,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
(struct em28xx *dev, struct urb *urb));
void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
void em28xx_stop_urbs(struct em28xx *dev);
-int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
void em28xx_wake_i2c(struct em28xx *dev);
@@ -712,16 +715,18 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
/* Provided by em28xx-cards.c */
-extern int em2800_variant_detect(struct usb_device *udev, int model);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
-extern const unsigned int em28xx_bcount;
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
void em28xx_release_resources(struct em28xx *dev);
/* Provided by em28xx-vbi.c */
extern struct vb2_ops em28xx_vbi_qops;
+/* Provided by em28xx-camera.c */
+int em28xx_detect_sensor(struct em28xx *dev);
+int em28xx_init_camera(struct em28xx *dev);
+
/* printk macros */
#define em28xx_err(fmt, arg...) do {\
@@ -744,72 +749,6 @@ static inline int em28xx_compression_disable(struct em28xx *dev)
return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00);
}
-static inline int em28xx_contrast_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f;
-}
-
-static inline int em28xx_brightness_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R21_YOFFSET);
-}
-
-static inline int em28xx_saturation_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f;
-}
-
-static inline int em28xx_u_balance_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R23_UOFFSET);
-}
-
-static inline int em28xx_v_balance_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R24_VOFFSET);
-}
-
-static inline int em28xx_gamma_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f;
-}
-
-static inline int em28xx_contrast_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1);
-}
-
-static inline int em28xx_brightness_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1);
-}
-
-static inline int em28xx_saturation_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1);
-}
-
-static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1);
-}
-
-static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1);
-}
-
-static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1);
-}
-
/*FIXME: maxw should be dependent of alt mode */
static inline unsigned int norm_maxw(struct em28xx *dev)
{
diff --git a/drivers/media/usb/gspca/autogain_functions.h b/drivers/media/usb/gspca/autogain_functions.h
deleted file mode 100644
index d625eafe63e..00000000000
--- a/drivers/media/usb/gspca/autogain_functions.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Functions for auto gain.
- *
- * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef WANT_REGULAR_AUTOGAIN
-/* auto gain and exposure algorithm based on the knee algorithm described here:
- http://ytse.tricolour.net/docs/LowLightOptimization.html
-
- Returns 0 if no changes were made, 1 if the gain and or exposure settings
- where changed. */
-static inline int auto_gain_n_exposure(
- struct gspca_dev *gspca_dev,
- int avg_lum,
- int desired_avg_lum,
- int deadzone,
- int gain_knee,
- int exposure_knee)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i, steps, gain, orig_gain, exposure, orig_exposure;
- int retval = 0;
-
- orig_gain = gain = sd->ctrls[GAIN].val;
- orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
-
- /* If we are of a multiple of deadzone, do multiple steps to reach the
- desired lumination fast (with the risc of a slight overshoot) */
- steps = abs(desired_avg_lum - avg_lum) / deadzone;
-
- PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
- avg_lum, desired_avg_lum, steps);
-
- for (i = 0; i < steps; i++) {
- if (avg_lum > desired_avg_lum) {
- if (gain > gain_knee)
- gain--;
- else if (exposure > exposure_knee)
- exposure--;
- else if (gain > sd->ctrls[GAIN].def)
- gain--;
- else if (exposure > sd->ctrls[EXPOSURE].min)
- exposure--;
- else if (gain > sd->ctrls[GAIN].min)
- gain--;
- else
- break;
- } else {
- if (gain < sd->ctrls[GAIN].def)
- gain++;
- else if (exposure < exposure_knee)
- exposure++;
- else if (gain < gain_knee)
- gain++;
- else if (exposure < sd->ctrls[EXPOSURE].max)
- exposure++;
- else if (gain < sd->ctrls[GAIN].max)
- gain++;
- else
- break;
- }
- }
-
- if (gain != orig_gain) {
- sd->ctrls[GAIN].val = gain;
- setgain(gspca_dev);
- retval = 1;
- }
- if (exposure != orig_exposure) {
- sd->ctrls[EXPOSURE].val = exposure;
- setexposure(gspca_dev);
- retval = 1;
- }
-
- if (retval)
- PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
- gain, exposure);
- return retval;
-}
-#endif
-
-#ifdef WANT_COARSE_EXPO_AUTOGAIN
-/* Autogain + exposure algorithm for cameras with a coarse exposure control
- (usually this means we can only control the clockdiv to change exposure)
- As changing the clockdiv so that the fps drops from 30 to 15 fps for
- example, will lead to a huge exposure change (it effectively doubles),
- this algorithm normally tries to only adjust the gain (between 40 and
- 80 %) and if that does not help, only then changes exposure. This leads
- to a much more stable image then using the knee algorithm which at
- certain points of the knee graph will only try to adjust exposure,
- which leads to oscilating as one exposure step is huge.
-
- Note this assumes that the sd struct for the cam in question has
- exp_too_low_cnt and exp_too_high_cnt int members for use by this function.
-
- Returns 0 if no changes were made, 1 if the gain and or exposure settings
- where changed. */
-static inline int coarse_grained_expo_autogain(
- struct gspca_dev *gspca_dev,
- int avg_lum,
- int desired_avg_lum,
- int deadzone)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int steps, gain, orig_gain, exposure, orig_exposure;
- int gain_low, gain_high;
- int retval = 0;
-
- orig_gain = gain = sd->ctrls[GAIN].val;
- orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
-
- gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2;
- gain_low += sd->ctrls[GAIN].min;
- gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4;
- gain_high += sd->ctrls[GAIN].min;
-
- /* If we are of a multiple of deadzone, do multiple steps to reach the
- desired lumination fast (with the risc of a slight overshoot) */
- steps = (desired_avg_lum - avg_lum) / deadzone;
-
- PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
- avg_lum, desired_avg_lum, steps);
-
- if ((gain + steps) > gain_high &&
- exposure < sd->ctrls[EXPOSURE].max) {
- gain = gain_high;
- sd->exp_too_low_cnt++;
- sd->exp_too_high_cnt = 0;
- } else if ((gain + steps) < gain_low &&
- exposure > sd->ctrls[EXPOSURE].min) {
- gain = gain_low;
- sd->exp_too_high_cnt++;
- sd->exp_too_low_cnt = 0;
- } else {
- gain += steps;
- if (gain > sd->ctrls[GAIN].max)
- gain = sd->ctrls[GAIN].max;
- else if (gain < sd->ctrls[GAIN].min)
- gain = sd->ctrls[GAIN].min;
- sd->exp_too_high_cnt = 0;
- sd->exp_too_low_cnt = 0;
- }
-
- if (sd->exp_too_high_cnt > 3) {
- exposure--;
- sd->exp_too_high_cnt = 0;
- } else if (sd->exp_too_low_cnt > 3) {
- exposure++;
- sd->exp_too_low_cnt = 0;
- }
-
- if (gain != orig_gain) {
- sd->ctrls[GAIN].val = gain;
- setgain(gspca_dev);
- retval = 1;
- }
- if (exposure != orig_exposure) {
- sd->ctrls[EXPOSURE].val = exposure;
- setexposure(gspca_dev);
- retval = 1;
- }
-
- if (retval)
- PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
- gain, exposure);
- return retval;
-}
-#endif
diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c
index 352f32190e6..05f406deae1 100644
--- a/drivers/media/usb/gspca/benq.c
+++ b/drivers/media/usb/gspca/benq.c
@@ -186,7 +186,7 @@ static void sd_isoc_irq(struct urb *urb)
/* check the packet status and length */
if (urb0->iso_frame_desc[i].actual_length != SD_PKT_SZ
|| urb->iso_frame_desc[i].actual_length != SD_PKT_SZ) {
- PDEBUG(D_ERR, "ISOC bad lengths %d / %d",
+ PERR("ISOC bad lengths %d / %d",
urb0->iso_frame_desc[i].actual_length,
urb->iso_frame_desc[i].actual_length);
gspca_dev->last_packet_type = DISCARD_PACKET;
diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c
index c9052f20435..38714df31ac 100644
--- a/drivers/media/usb/gspca/conex.c
+++ b/drivers/media/usb/gspca/conex.c
@@ -73,12 +73,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_r: buffer overflow\n");
+ PERR("reg_r: buffer overflow\n");
return;
}
-#endif
+
usb_control_msg(dev,
usb_rcvctrlpipe(dev, 0),
0,
@@ -113,13 +112,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_w: buffer overflow\n");
+ PERR("reg_w: buffer overflow\n");
return;
}
PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
-#endif
+
memcpy(gspca_dev->usb_buf, buffer, len);
usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -689,7 +687,7 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev)
reg_w_val(gspca_dev, 0x0053, 0x00);
} while (--retry);
if (retry == 0)
- PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
+ PERR("Damned Errors sending jpeg Table");
/* send the qtable now */
reg_r(gspca_dev, 0x0001, 1); /* -> 0x18 */
length = 8;
diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
index 1dcdd9f95f1..064b53043b1 100644
--- a/drivers/media/usb/gspca/cpia1.c
+++ b/drivers/media/usb/gspca/cpia1.c
@@ -421,8 +421,7 @@ static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command)
pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE;
} else {
- PDEBUG(D_ERR, "Unexpected first byte of command: %x",
- command[0]);
+ PERR("Unexpected first byte of command: %x", command[0]);
return -EINVAL;
}
@@ -701,7 +700,7 @@ static void reset_camera_params(struct gspca_dev *gspca_dev)
params->qx3.cradled = 0;
}
-static void printstatus(struct cam_params *params)
+static void printstatus(struct gspca_dev *gspca_dev, struct cam_params *params)
{
PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x",
params->status.systemState, params->status.grabState,
@@ -725,10 +724,9 @@ static int goto_low_power(struct gspca_dev *gspca_dev)
if (sd->params.status.systemState != LO_POWER_STATE) {
if (sd->params.status.systemState != WARM_BOOT_STATE) {
- PDEBUG(D_ERR,
- "unexpected state after lo power cmd: %02x",
- sd->params.status.systemState);
- printstatus(&sd->params);
+ PERR("unexpected state after lo power cmd: %02x",
+ sd->params.status.systemState);
+ printstatus(gspca_dev, &sd->params);
}
return -EIO;
}
@@ -756,9 +754,9 @@ static int goto_high_power(struct gspca_dev *gspca_dev)
return ret;
if (sd->params.status.systemState != HI_POWER_STATE) {
- PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x",
- sd->params.status.systemState);
- printstatus(&sd->params);
+ PERR("unexpected state after hi power cmd: %02x",
+ sd->params.status.systemState);
+ printstatus(gspca_dev, &sd->params);
return -EIO;
}
@@ -1449,8 +1447,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->params.version.firmwareVersion = 0;
get_version_information(gspca_dev);
if (sd->params.version.firmwareVersion != 1) {
- PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)",
- sd->params.version.firmwareVersion);
+ PERR("only firmware version 1 is supported (got: %d)",
+ sd->params.version.firmwareVersion);
return -ENODEV;
}
@@ -1475,9 +1473,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* Start the camera in low power mode */
if (goto_low_power(gspca_dev)) {
if (sd->params.status.systemState != WARM_BOOT_STATE) {
- PDEBUG(D_ERR, "unexpected systemstate: %02x",
- sd->params.status.systemState);
- printstatus(&sd->params);
+ PERR("unexpected systemstate: %02x",
+ sd->params.status.systemState);
+ printstatus(gspca_dev, &sd->params);
return -ENODEV;
}
@@ -1523,9 +1521,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
return ret;
if (sd->params.status.fatalError) {
- PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x",
- sd->params.status.fatalError,
- sd->params.status.vpStatus);
+ PERR("fatal_error: %04x, vp_status: %04x",
+ sd->params.status.fatalError, sd->params.status.vpStatus);
return -EIO;
}
diff --git a/drivers/media/usb/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c
index 38f68e11c3a..26c9ee1f104 100644
--- a/drivers/media/usb/gspca/etoms.c
+++ b/drivers/media/usb/gspca/etoms.c
@@ -163,12 +163,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_r: buffer overflow\n");
+ PERR("reg_r: buffer overflow\n");
return;
}
-#endif
+
usb_control_msg(dev,
usb_rcvctrlpipe(dev, 0),
0,
@@ -201,13 +200,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
pr_err("reg_w: buffer overflow\n");
return;
}
PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
-#endif
+
memcpy(gspca_dev->usb_buf, buffer, len);
usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -274,7 +272,7 @@ static int et_video(struct gspca_dev *gspca_dev,
: 0); /* stopvideo */
ret = Et_WaitStatus(gspca_dev);
if (ret != 0)
- PDEBUG(D_ERR, "timeout video on/off");
+ PERR("timeout video on/off");
return ret;
}
@@ -768,9 +766,7 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
-#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
-#endif
{}
};
diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c
index ced3b71f14e..cb1e64ca59c 100644
--- a/drivers/media/usb/gspca/gl860/gl860.c
+++ b/drivers/media/usb/gspca/gl860/gl860.c
@@ -58,115 +58,135 @@ MODULE_PARM_DESC(sensor,
/*============================ webcam controls =============================*/
-/* Functions to get and set a control value */
-#define SD_SETGET(thename) \
-static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\
-{\
- struct sd *sd = (struct sd *) gspca_dev;\
-\
- sd->vcur.thename = val;\
- if (gspca_dev->streaming)\
- sd->waitSet = 1;\
- return 0;\
-} \
-static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
-{\
- struct sd *sd = (struct sd *) gspca_dev;\
-\
- *val = sd->vcur.thename;\
- return 0;\
-}
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
-SD_SETGET(mirror)
-SD_SETGET(flip)
-SD_SETGET(AC50Hz)
-SD_SETGET(backlight)
-SD_SETGET(brightness)
-SD_SETGET(gamma)
-SD_SETGET(hue)
-SD_SETGET(saturation)
-SD_SETGET(sharpness)
-SD_SETGET(whitebal)
-SD_SETGET(contrast)
-
-#define GL860_NCTRLS 11
-
-/* control table */
-static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
-static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
-static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
-static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
-
-#define SET_MY_CTRL(theid, \
- thetype, thelabel, thename) \
- if (sd->vmax.thename != 0) {\
- sd_ctrls[nCtrls].qctrl.id = theid;\
- sd_ctrls[nCtrls].qctrl.type = thetype;\
- strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\
- sd_ctrls[nCtrls].qctrl.minimum = 0;\
- sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\
- sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\
- sd_ctrls[nCtrls].qctrl.step = \
- (sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\
- sd_ctrls[nCtrls].set = sd_set_##thename;\
- sd_ctrls[nCtrls].get = sd_get_##thename;\
- nCtrls++;\
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ sd->vcur.brightness = ctrl->val;
+ break;
+ case V4L2_CID_CONTRAST:
+ sd->vcur.contrast = ctrl->val;
+ break;
+ case V4L2_CID_SATURATION:
+ sd->vcur.saturation = ctrl->val;
+ break;
+ case V4L2_CID_HUE:
+ sd->vcur.hue = ctrl->val;
+ break;
+ case V4L2_CID_GAMMA:
+ sd->vcur.gamma = ctrl->val;
+ break;
+ case V4L2_CID_HFLIP:
+ sd->vcur.mirror = ctrl->val;
+ break;
+ case V4L2_CID_VFLIP:
+ sd->vcur.flip = ctrl->val;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ sd->vcur.AC50Hz = ctrl->val;
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ sd->vcur.whitebal = ctrl->val;
+ break;
+ case V4L2_CID_SHARPNESS:
+ sd->vcur.sharpness = ctrl->val;
+ break;
+ case V4L2_CID_BACKLIGHT_COMPENSATION:
+ sd->vcur.backlight = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
}
-static int gl860_build_control_table(struct gspca_dev *gspca_dev)
+ if (gspca_dev->streaming)
+ sd->waitSet = 1;
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct ctrl *sd_ctrls;
- int nCtrls = 0;
-
- if (_MI1320_)
- sd_ctrls = sd_ctrls_mi1320;
- else if (_MI2020_)
- sd_ctrls = sd_ctrls_mi2020;
- else if (_OV2640_)
- sd_ctrls = sd_ctrls_ov2640;
- else if (_OV9655_)
- sd_ctrls = sd_ctrls_ov9655;
- else
- return 0;
-
- memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl));
-
- SET_MY_CTRL(V4L2_CID_BRIGHTNESS,
- V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness)
- SET_MY_CTRL(V4L2_CID_SHARPNESS,
- V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness)
- SET_MY_CTRL(V4L2_CID_CONTRAST,
- V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast)
- SET_MY_CTRL(V4L2_CID_GAMMA,
- V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma)
- SET_MY_CTRL(V4L2_CID_HUE,
- V4L2_CTRL_TYPE_INTEGER, "Palette", hue)
- SET_MY_CTRL(V4L2_CID_SATURATION,
- V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation)
- SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE,
- V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal)
- SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION,
- V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight)
-
- SET_MY_CTRL(V4L2_CID_HFLIP,
- V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror)
- SET_MY_CTRL(V4L2_CID_VFLIP,
- V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip)
- SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CTRL_TYPE_BOOLEAN, "AC power 50Hz", AC50Hz)
-
- return nCtrls;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 11);
+
+ if (sd->vmax.brightness)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ 0, sd->vmax.brightness, 1,
+ sd->vcur.brightness);
+
+ if (sd->vmax.contrast)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_CONTRAST,
+ 0, sd->vmax.contrast, 1,
+ sd->vcur.contrast);
+
+ if (sd->vmax.saturation)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SATURATION,
+ 0, sd->vmax.saturation, 1,
+ sd->vcur.saturation);
+
+ if (sd->vmax.hue)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HUE,
+ 0, sd->vmax.hue, 1, sd->vcur.hue);
+
+ if (sd->vmax.gamma)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAMMA,
+ 0, sd->vmax.gamma, 1, sd->vcur.gamma);
+
+ if (sd->vmax.mirror)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HFLIP,
+ 0, sd->vmax.mirror, 1, sd->vcur.mirror);
+
+ if (sd->vmax.flip)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_VFLIP,
+ 0, sd->vmax.flip, 1, sd->vcur.flip);
+
+ if (sd->vmax.AC50Hz)
+ v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ sd->vmax.AC50Hz, 0, sd->vcur.AC50Hz);
+
+ if (sd->vmax.whitebal)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ 0, sd->vmax.whitebal, 1, sd->vcur.whitebal);
+
+ if (sd->vmax.sharpness)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SHARPNESS,
+ 0, sd->vmax.sharpness, 1,
+ sd->vcur.sharpness);
+
+ if (sd->vmax.backlight)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BACKLIGHT_COMPENSATION,
+ 0, sd->vmax.backlight, 1,
+ sd->vcur.backlight);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ return 0;
}
/*==================== sud-driver structure initialisation =================*/
static const struct sd_desc sd_desc_mi1320 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_mi1320,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -176,10 +196,9 @@ static const struct sd_desc sd_desc_mi1320 = {
static const struct sd_desc sd_desc_mi2020 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_mi2020,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -189,10 +208,9 @@ static const struct sd_desc sd_desc_mi2020 = {
static const struct sd_desc sd_desc_ov2640 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_ov2640,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -202,10 +220,9 @@ static const struct sd_desc sd_desc_ov2640 = {
static const struct sd_desc sd_desc_ov9655 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_ov9655,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -371,7 +388,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
dev_init_settings(gspca_dev);
if (AC50Hz != 0xff)
((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz;
- gl860_build_control_table(gspca_dev);
return 0;
}
@@ -566,7 +582,7 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n",
r, pref, req, val, index, len);
else if (len > 1 && r < len)
- PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
+ PERR("short ctrl transfer %d/%d", r, len);
msleep(1);
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 3564bdbb2ea..5995ec4de6b 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -60,14 +60,14 @@ MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(GSPCA_VERSION);
-#ifdef GSPCA_DEBUG
-int gspca_debug = D_ERR | D_PROBE;
+int gspca_debug;
EXPORT_SYMBOL(gspca_debug);
-static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
+static void PDEBUG_MODE(struct gspca_dev *gspca_dev, int debug, char *txt,
+ __u32 pixfmt, int w, int h)
{
if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') {
- PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d",
+ PDEBUG(debug, "%s %c%c%c%c %dx%d",
txt,
pixfmt & 0xff,
(pixfmt >> 8) & 0xff,
@@ -75,15 +75,12 @@ static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
pixfmt >> 24,
w, h);
} else {
- PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d",
+ PDEBUG(debug, "%s 0x%08x %dx%d",
txt,
pixfmt,
w, h);
}
}
-#else
-#define PDEBUG_MODE(txt, pixfmt, w, h)
-#endif
/* specific memory types - !! should be different from V4L2_MEMORY_xxx */
#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */
@@ -129,7 +126,7 @@ static void int_irq(struct urb *urb)
case 0:
if (gspca_dev->sd_desc->int_pkt_scan(gspca_dev,
urb->transfer_buffer, urb->actual_length) < 0) {
- PDEBUG(D_ERR, "Unknown packet received");
+ PERR("Unknown packet received");
}
break;
@@ -143,7 +140,7 @@ static void int_irq(struct urb *urb)
break;
default:
- PDEBUG(D_ERR, "URB error %i, resubmitting", urb->status);
+ PERR("URB error %i, resubmitting", urb->status);
urb->status = 0;
ret = 0;
}
@@ -229,7 +226,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
- PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
+ PERR("submit int URB failed with error %i", ret);
goto error_submit;
}
gspca_dev->int_urb = urb;
@@ -315,7 +312,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
if (gspca_dev->frozen)
return;
#endif
- PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ PERR("urb status: %d", urb->status);
urb->status = 0;
goto resubmit;
}
@@ -388,7 +385,7 @@ static void bulk_irq(struct urb *urb)
if (gspca_dev->frozen)
return;
#endif
- PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ PERR("urb status: %d", urb->status);
urb->status = 0;
goto resubmit;
}
@@ -460,7 +457,7 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
/* append the packet to the frame buffer */
if (len > 0) {
if (gspca_dev->image_len + len > gspca_dev->frsz) {
- PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+ PERR("frame overflow %d > %d",
gspca_dev->image_len + len,
gspca_dev->frsz);
packet_type = DISCARD_PACKET;
@@ -570,11 +567,10 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
gspca_dev->urb[i] = NULL;
usb_kill_urb(urb);
- if (urb->transfer_buffer != NULL)
- usb_free_coherent(gspca_dev->dev,
- urb->transfer_buffer_length,
- urb->transfer_buffer,
- urb->transfer_dma);
+ usb_free_coherent(gspca_dev->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
usb_free_urb(urb);
}
}
@@ -960,9 +956,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* the bandwidth is not wide enough
* negotiate or try a lower alternate setting */
retry:
- PDEBUG(D_ERR|D_STREAM,
- "alt %d - bandwidth not wide enough - trying again",
- alt);
+ PERR("alt %d - bandwidth not wide enough, trying again", alt);
msleep(20); /* wait for kill complete */
if (gspca_dev->sd_desc->isoc_nego) {
ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
@@ -984,7 +978,6 @@ out:
static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
{
- struct gspca_ctrl *ctrl;
int i;
i = gspca_dev->cam.nmodes - 1; /* take the highest mode */
@@ -993,17 +986,8 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
- /* set the current control values to their default values
- * which may have changed in sd_init() */
/* does nothing if ctrl_handler == NULL */
v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
- ctrl = gspca_dev->cam.ctrls;
- if (ctrl != NULL) {
- for (i = 0;
- i < gspca_dev->sd_desc->nctrls;
- i++, ctrl++)
- ctrl->val = ctrl->def;
- }
}
static int wxh_to_mode(struct gspca_dev *gspca_dev,
@@ -1055,7 +1039,7 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct gspca_dev *gspca_dev = video_drvdata(file);
@@ -1137,10 +1121,9 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
-#ifdef GSPCA_DEBUG
- if (gspca_debug & D_CONF)
- PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
-#endif
+ PDEBUG_MODE(gspca_dev, D_CONF, "try fmt cap",
+ fmt->fmt.pix.pixelformat, w, h);
+
/* search the closest mode for width and height */
mode = wxh_to_mode(gspca_dev, w, h);
@@ -1153,8 +1136,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
fmt->fmt.pix.pixelformat);
if (mode2 >= 0)
mode = mode2;
-/* else
- ; * no chance, return this mode */
}
fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
/* some drivers use priv internally, zero it before giving it to
@@ -1290,15 +1271,6 @@ static int dev_open(struct file *file)
if (!try_module_get(gspca_dev->module))
return -ENODEV;
-#ifdef GSPCA_DEBUG
- /* activate the v4l2 debug */
- if (gspca_debug & D_V4L2)
- gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL
- | V4L2_DEBUG_IOCTL_ARG;
- else
- gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
- | V4L2_DEBUG_IOCTL_ARG);
-#endif
return v4l2_fh_open(file);
}
@@ -1357,134 +1329,6 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int get_ctrl(struct gspca_dev *gspca_dev,
- int id)
-{
- const struct ctrl *ctrls;
- int i;
-
- for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
- i < gspca_dev->sd_desc->nctrls;
- i++, ctrls++) {
- if (gspca_dev->ctrl_dis & (1 << i))
- continue;
- if (id == ctrls->qctrl.id)
- return i;
- }
- return -1;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *q_ctrl)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
- const struct ctrl *ctrls;
- struct gspca_ctrl *gspca_ctrl;
- int i, idx;
- u32 id;
-
- id = q_ctrl->id;
- if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
- id &= V4L2_CTRL_ID_MASK;
- id++;
- idx = -1;
- for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
- if (gspca_dev->ctrl_dis & (1 << i))
- continue;
- if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
- continue;
- if (idx >= 0
- && gspca_dev->sd_desc->ctrls[i].qctrl.id
- > gspca_dev->sd_desc->ctrls[idx].qctrl.id)
- continue;
- idx = i;
- }
- } else {
- idx = get_ctrl(gspca_dev, id);
- }
- if (idx < 0)
- return -EINVAL;
- ctrls = &gspca_dev->sd_desc->ctrls[idx];
- memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl);
- if (gspca_dev->cam.ctrls != NULL) {
- gspca_ctrl = &gspca_dev->cam.ctrls[idx];
- q_ctrl->default_value = gspca_ctrl->def;
- q_ctrl->minimum = gspca_ctrl->min;
- q_ctrl->maximum = gspca_ctrl->max;
- }
- if (gspca_dev->ctrl_inac & (1 << idx))
- q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
- const struct ctrl *ctrls;
- struct gspca_ctrl *gspca_ctrl;
- int idx;
-
- idx = get_ctrl(gspca_dev, ctrl->id);
- if (idx < 0)
- return -EINVAL;
- if (gspca_dev->ctrl_inac & (1 << idx))
- return -EINVAL;
- ctrls = &gspca_dev->sd_desc->ctrls[idx];
- if (gspca_dev->cam.ctrls != NULL) {
- gspca_ctrl = &gspca_dev->cam.ctrls[idx];
- if (ctrl->value < gspca_ctrl->min
- || ctrl->value > gspca_ctrl->max)
- return -ERANGE;
- } else {
- gspca_ctrl = NULL;
- if (ctrl->value < ctrls->qctrl.minimum
- || ctrl->value > ctrls->qctrl.maximum)
- return -ERANGE;
- }
- PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
- gspca_dev->usb_err = 0;
- if (ctrls->set != NULL)
- return ctrls->set(gspca_dev, ctrl->value);
- if (gspca_ctrl != NULL) {
- gspca_ctrl->val = ctrl->value;
- if (ctrls->set_control != NULL
- && gspca_dev->streaming)
- ctrls->set_control(gspca_dev);
- }
- return gspca_dev->usb_err;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
- const struct ctrl *ctrls;
- int idx;
-
- idx = get_ctrl(gspca_dev, ctrl->id);
- if (idx < 0)
- return -EINVAL;
- ctrls = &gspca_dev->sd_desc->ctrls[idx];
-
- gspca_dev->usb_err = 0;
- if (ctrls->get != NULL)
- return ctrls->get(gspca_dev, &ctrl->value);
- if (gspca_dev->cam.ctrls != NULL)
- ctrl->value = gspca_dev->cam.ctrls[idx].val;
- return 0;
-}
-
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *qmenu)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
-
- if (!gspca_dev->sd_desc->querymenu)
- return -ENOTTY;
- return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
-}
-
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *input)
{
@@ -1621,14 +1465,8 @@ static int vidioc_streamon(struct file *file, void *priv,
if (ret < 0)
goto out;
}
-#ifdef GSPCA_DEBUG
- if (gspca_debug & D_STREAM) {
- PDEBUG_MODE("stream on OK",
- gspca_dev->pixfmt,
- gspca_dev->width,
- gspca_dev->height);
- }
-#endif
+ PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK", gspca_dev->pixfmt,
+ gspca_dev->width, gspca_dev->height);
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
@@ -1879,8 +1717,7 @@ static int vidioc_dqbuf(struct file *file, void *priv,
if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
frame->data,
frame->v4l2_buf.bytesused)) {
- PDEBUG(D_ERR|D_STREAM,
- "dqbuf cp to user failed");
+ PERR("dqbuf cp to user failed");
ret = -EFAULT;
}
}
@@ -2092,8 +1929,7 @@ static ssize_t dev_read(struct file *file, char __user *data,
count = frame->v4l2_buf.bytesused;
ret = copy_to_user(data, frame->data, count);
if (ret != 0) {
- PDEBUG(D_ERR|D_STREAM,
- "read cp to user lack %d / %zd", ret, count);
+ PERR("read cp to user lack %d / %zd", ret, count);
ret = -EFAULT;
goto out;
}
@@ -2125,10 +1961,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_streamon = vidioc_streamon,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_querymenu = vidioc_querymenu,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -2157,22 +1989,6 @@ static const struct video_device gspca_template = {
.release = video_device_release_empty, /* We use v4l2_dev.release */
};
-/* initialize the controls */
-static void ctrls_init(struct gspca_dev *gspca_dev)
-{
- struct gspca_ctrl *ctrl;
- int i;
-
- for (i = 0, ctrl = gspca_dev->cam.ctrls;
- i < gspca_dev->sd_desc->nctrls;
- i++, ctrl++) {
- ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value;
- ctrl->val = ctrl->def;
- ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum;
- ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum;
- }
-}
-
/*
* probe and create a new gspca device
*
@@ -2249,8 +2065,6 @@ int gspca_dev_probe2(struct usb_interface *intf,
ret = sd_desc->config(gspca_dev, id);
if (ret < 0)
goto out;
- if (gspca_dev->cam.ctrls != NULL)
- ctrls_init(gspca_dev);
ret = sd_desc->init(gspca_dev);
if (ret < 0)
goto out;
@@ -2450,10 +2264,6 @@ static void __exit gspca_exit(void)
module_init(gspca_init);
module_exit(gspca_exit);
-#ifdef GSPCA_DEBUG
module_param_named(debug, gspca_debug, int, 0644);
MODULE_PARM_DESC(debug,
- "Debug (bit) 0x01:error 0x02:probe 0x04:config"
- " 0x08:stream 0x10:frame 0x20:packet"
- " 0x0100: v4l2");
-#endif
+ "1:probe 2:config 3:stream 4:frame 5:packet 6:usbi 7:usbo");
diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h
index 5559932bf2f..ef8efeb8007 100644
--- a/drivers/media/usb/gspca/gspca.h
+++ b/drivers/media/usb/gspca/gspca.h
@@ -10,30 +10,26 @@
#include <media/v4l2-device.h>
#include <linux/mutex.h>
-/* compilation option */
-/*#define GSPCA_DEBUG 1*/
-#ifdef GSPCA_DEBUG
-/* GSPCA our debug messages */
+
+/* GSPCA debug codes */
+
+#define D_PROBE 1
+#define D_CONF 2
+#define D_STREAM 3
+#define D_FRAM 4
+#define D_PACK 5
+#define D_USBI 6
+#define D_USBO 7
+
extern int gspca_debug;
-#define PDEBUG(level, fmt, ...) \
-do { \
- if (gspca_debug & (level)) \
- pr_info(fmt, ##__VA_ARGS__); \
-} while (0)
-#define D_ERR 0x01
-#define D_PROBE 0x02
-#define D_CONF 0x04
-#define D_STREAM 0x08
-#define D_FRAM 0x10
-#define D_PACK 0x20
-#define D_USBI 0x00
-#define D_USBO 0x00
-#define D_V4L2 0x0100
-#else
-#define PDEBUG(level, fmt, ...) do {} while(0)
-#endif
+
+#define PDEBUG(level, fmt, ...) \
+ v4l2_dbg(level, gspca_debug, &gspca_dev->v4l2_dev, fmt, ##__VA_ARGS__)
+
+#define PERR(fmt, ...) \
+ v4l2_err(&gspca_dev->v4l2_dev, fmt, ##__VA_ARGS__)
#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
/* image transfers */
@@ -46,20 +42,11 @@ struct framerates {
int nrates;
};
-/* control definition */
-struct gspca_ctrl {
- s16 val; /* current value */
- s16 def; /* default value */
- s16 min, max; /* minimum and maximum values */
-};
-
/* device information - set at probe time */
struct cam {
const struct v4l2_pix_format *cam_mode; /* size nmodes */
const struct framerates *mode_framerates; /* must have size nmodes,
* just like cam_mode */
- struct gspca_ctrl *ctrls; /* control table - size nctrls */
- /* may be NULL */
u32 bulk_size; /* buffer size when image transfer by bulk */
u32 input_flags; /* value for ENUM_INPUT status flags */
u8 nmodes; /* size of cam_mode */
@@ -87,14 +74,14 @@ typedef int (*cam_get_jpg_op) (struct gspca_dev *,
struct v4l2_jpegcompression *);
typedef int (*cam_set_jpg_op) (struct gspca_dev *,
const struct v4l2_jpegcompression *);
-typedef int (*cam_reg_op) (struct gspca_dev *,
+typedef int (*cam_get_reg_op) (struct gspca_dev *,
struct v4l2_dbg_register *);
+typedef int (*cam_set_reg_op) (struct gspca_dev *,
+ const struct v4l2_dbg_register *);
typedef int (*cam_ident_op) (struct gspca_dev *,
struct v4l2_dbg_chip_ident *);
typedef void (*cam_streamparm_op) (struct gspca_dev *,
struct v4l2_streamparm *);
-typedef int (*cam_qmnu_op) (struct gspca_dev *,
- struct v4l2_querymenu *);
typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
u8 *data,
int len);
@@ -102,20 +89,10 @@ typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev,
u8 *data,
int len);
-struct ctrl {
- struct v4l2_queryctrl qctrl;
- int (*set)(struct gspca_dev *, __s32);
- int (*get)(struct gspca_dev *, __s32 *);
- cam_v_op set_control;
-};
-
/* subdriver description */
struct sd_desc {
/* information */
const char *name; /* sub-driver name */
-/* controls */
- const struct ctrl *ctrls; /* static control definition */
- int nctrls;
/* mandatory operations */
cam_cf_op config; /* called on probe */
cam_op init; /* called on probe and resume */
@@ -130,12 +107,11 @@ struct sd_desc {
cam_v_op dq_callback; /* called when a frame has been dequeued */
cam_get_jpg_op get_jcomp;
cam_set_jpg_op set_jcomp;
- cam_qmnu_op querymenu;
cam_streamparm_op get_streamparm;
cam_streamparm_op set_streamparm;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- cam_reg_op set_register;
- cam_reg_op get_register;
+ cam_set_reg_op set_register;
+ cam_get_reg_op get_register;
#endif
cam_ident_op get_chip_ident;
#if IS_ENABLED(CONFIG_INPUT)
@@ -174,8 +150,6 @@ struct gspca_dev {
struct cam cam; /* device information */
const struct sd_desc *sd_desc; /* subdriver description */
- unsigned ctrl_dis; /* disabled controls (bit map) */
- unsigned ctrl_inac; /* inactive controls (bit map) */
struct v4l2_ctrl_handler ctrl_handler;
/* autogain and exposure or gain control cluster, these are global as
diff --git a/drivers/media/usb/gspca/jeilinj.c b/drivers/media/usb/gspca/jeilinj.c
index 1ba29fe7fad..8da3dde3838 100644
--- a/drivers/media/usb/gspca/jeilinj.c
+++ b/drivers/media/usb/gspca/jeilinj.c
@@ -266,7 +266,7 @@ static int jlj_start(struct gspca_dev *gspca_dev)
msleep(2);
setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
if (gspca_dev->usb_err < 0)
- PDEBUG(D_ERR, "Start streaming command failed");
+ PERR("Start streaming command failed");
return gspca_dev->usb_err;
}
diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c
index 61e25dbf244..39c96bb4c98 100644
--- a/drivers/media/usb/gspca/konica.c
+++ b/drivers/media/usb/gspca/konica.c
@@ -277,7 +277,7 @@ static void sd_isoc_irq(struct urb *urb)
if (gspca_dev->frozen)
return;
#endif
- PDEBUG(D_ERR, "urb status: %d", urb->status);
+ PERR("urb status: %d", urb->status);
st = usb_submit_urb(urb, GFP_ATOMIC);
if (st < 0)
pr_err("resubmit urb error %d\n", st);
@@ -295,33 +295,30 @@ static void sd_isoc_irq(struct urb *urb)
sd->last_data_urb = NULL;
if (!data_urb || data_urb->start_frame != status_urb->start_frame) {
- PDEBUG(D_ERR|D_PACK, "lost sync on frames");
+ PERR("lost sync on frames");
goto resubmit;
}
if (data_urb->number_of_packets != status_urb->number_of_packets) {
- PDEBUG(D_ERR|D_PACK,
- "no packets does not match, data: %d, status: %d",
- data_urb->number_of_packets,
- status_urb->number_of_packets);
+ PERR("no packets does not match, data: %d, status: %d",
+ data_urb->number_of_packets,
+ status_urb->number_of_packets);
goto resubmit;
}
for (i = 0; i < status_urb->number_of_packets; i++) {
if (data_urb->iso_frame_desc[i].status ||
status_urb->iso_frame_desc[i].status) {
- PDEBUG(D_ERR|D_PACK,
- "pkt %d data-status %d, status-status %d", i,
- data_urb->iso_frame_desc[i].status,
- status_urb->iso_frame_desc[i].status);
+ PERR("pkt %d data-status %d, status-status %d", i,
+ data_urb->iso_frame_desc[i].status,
+ status_urb->iso_frame_desc[i].status);
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
}
if (status_urb->iso_frame_desc[i].actual_length != 1) {
- PDEBUG(D_ERR|D_PACK,
- "bad status packet length %d",
- status_urb->iso_frame_desc[i].actual_length);
+ PERR("bad status packet length %d",
+ status_urb->iso_frame_desc[i].actual_length);
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
}
@@ -366,12 +363,11 @@ resubmit:
if (data_urb) {
st = usb_submit_urb(data_urb, GFP_ATOMIC);
if (st < 0)
- PDEBUG(D_ERR|D_PACK,
- "usb_submit_urb(data_urb) ret %d", st);
+ PERR("usb_submit_urb(data_urb) ret %d", st);
}
st = usb_submit_urb(status_urb, GFP_ATOMIC);
if (st < 0)
- pr_err("usb_submit_urb(status_urb) ret %d\n", st);
+ PERR("usb_submit_urb(status_urb) ret %d\n", st);
}
static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/usb/gspca/m5602/m5602_bridge.h b/drivers/media/usb/gspca/m5602/m5602_bridge.h
index 51af3ee3ab8..19eb1a64f9d 100644
--- a/drivers/media/usb/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/usb/gspca/m5602/m5602_bridge.h
@@ -136,16 +136,33 @@ struct sd {
/* A pointer to the currently connected sensor */
const struct m5602_sensor *sensor;
- struct sd_desc *desc;
-
- /* Sensor private data */
- void *sensor_priv;
-
/* The current frame's id, used to detect frame boundaries */
u8 frame_id;
/* The current frame count */
u32 frame_count;
+
+ /* Camera rotation polling thread for "flipable" cams */
+ struct task_struct *rotation_thread;
+
+ struct { /* auto-white-bal + green/red/blue balance control cluster */
+ struct v4l2_ctrl *auto_white_bal;
+ struct v4l2_ctrl *red_bal;
+ struct v4l2_ctrl *blue_bal;
+ struct v4l2_ctrl *green_bal;
+ };
+ struct { /* autoexpo / expo cluster */
+ struct v4l2_ctrl *autoexpo;
+ struct v4l2_ctrl *expo;
+ };
+ struct { /* autogain / gain cluster */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *gain;
+ };
+ struct { /* hflip/vflip cluster */
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
};
int m5602_read_bridge(
diff --git a/drivers/media/usb/gspca/m5602/m5602_core.c b/drivers/media/usb/gspca/m5602/m5602_core.c
index ed22638978c..d926e62cb80 100644
--- a/drivers/media/usb/gspca/m5602/m5602_core.c
+++ b/drivers/media/usb/gspca/m5602/m5602_core.c
@@ -41,6 +41,7 @@ MODULE_DEVICE_TABLE(usb, m5602_table);
int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -62,6 +63,7 @@ int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -98,6 +100,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
u8 *i2c_data, const u8 len)
{
int err, i;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
if (!len || len > sd->sensor->i2c_regW)
return -EINVAL;
@@ -147,6 +150,7 @@ int m5602_write_sensor(struct sd *sd, const u8 address,
{
int err, i;
u8 *p;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -252,6 +256,16 @@ static int m5602_init(struct gspca_dev *gspca_dev)
return err;
}
+static int m5602_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (!sd->sensor->init_controls)
+ return 0;
+
+ return sd->sensor->init_controls(sd);
+}
+
static int m5602_start_transfer(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -336,11 +350,12 @@ static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
sd->sensor->stop(sd);
}
-/* sub-driver description, the ctrl and nctrl is filled at probe time */
-static struct sd_desc sd_desc = {
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.config = m5602_configure,
.init = m5602_init,
+ .init_controls = m5602_init_controls,
.start = m5602_start_transfer,
.stopN = m5602_stop_transfer,
.pkt_scan = m5602_urb_complete
@@ -355,7 +370,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
int err;
cam = &gspca_dev->cam;
- sd->desc = &sd_desc;
if (dump_bridge)
m5602_dump_bridge(sd);
@@ -368,7 +382,7 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
return 0;
fail:
- PDEBUG(D_ERR, "ALi m5602 webcam failed");
+ PERR("ALi m5602 webcam failed");
cam->cam_mode = NULL;
cam->nmodes = 0;
diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
index 6268aa24ec5..cfa4663f893 100644
--- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
@@ -20,22 +20,8 @@
#include "m5602_mt9m111.h"
-static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl);
+static void mt9m111_dump_registers(struct sd *sd);
static struct v4l2_pix_format mt9m111_modes[] = {
{
@@ -50,118 +36,27 @@ static struct v4l2_pix_format mt9m111_modes[] = {
}
};
-static const struct ctrl mt9m111_ctrls[] = {
-#define VFLIP_IDX 0
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_vflip,
- .get = mt9m111_get_vflip
- },
-#define HFLIP_IDX 1
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_hflip,
- .get = mt9m111_get_hflip
- },
-#define GAIN_IDX 2
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0,
- .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
- .step = 1,
- .default_value = MT9M111_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_gain,
- .get = mt9m111_get_gain
- },
-#define AUTO_WHITE_BALANCE_IDX 3
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = mt9m111_set_auto_white_balance,
- .get = mt9m111_get_auto_white_balance
- },
-#define GREEN_BALANCE_IDX 4
- {
- {
- .id = M5602_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_GREEN_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_green_balance,
- .get = mt9m111_get_green_balance
- },
-#define BLUE_BALANCE_IDX 5
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_blue_balance,
- .get = mt9m111_get_blue_balance
- },
-#define RED_BALANCE_IDX 5
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_red_balance,
- .get = mt9m111_get_red_balance
- },
+static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
+ .s_ctrl = mt9m111_s_ctrl,
};
-static void mt9m111_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = {
+ .ops = &mt9m111_ctrl_ops,
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .name = "Green Balance",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 0x7ff,
+ .step = 1,
+ .def = MT9M111_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+};
int mt9m111_probe(struct sd *sd)
{
u8 data[2] = {0x00, 0x00};
int i;
- s32 *sensor_settings;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == MT9M111_SENSOR) {
@@ -200,19 +95,8 @@ int mt9m111_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
- GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = mt9m111_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
- sd->desc->ctrls = mt9m111_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
- sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
@@ -220,7 +104,6 @@ sensor_found:
int mt9m111_init(struct sd *sd)
{
int i, err = 0;
- s32 *sensor_settings = sd->sensor_priv;
/* Init the sensor */
for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
@@ -241,30 +124,45 @@ int mt9m111_init(struct sd *sd)
if (dump_sensor)
mt9m111_dump_registers(sd);
- err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = mt9m111_set_green_balance(&sd->gspca_dev,
- sensor_settings[GREEN_BALANCE_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = mt9m111_set_blue_balance(&sd->gspca_dev,
- sensor_settings[BLUE_BALANCE_IDX]);
- if (err < 0)
- return err;
+int mt9m111_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 7);
+
+ sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 0);
+ sd->green_bal = v4l2_ctrl_new_custom(hdl, &mt9m111_greenbal_cfg, NULL);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 0x7ff, 1,
+ MT9M111_RED_GAIN_DEFAULT);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 0x7ff, 1,
+ MT9M111_BLUE_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_GAIN, 0,
+ (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 1,
+ MT9M111_DEFAULT_GAIN);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
- err = mt9m111_set_red_balance(&sd->gspca_dev,
- sensor_settings[RED_BALANCE_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
- return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ return 0;
}
int mt9m111_start(struct sd *sd)
@@ -272,7 +170,7 @@ int mt9m111_start(struct sd *sd)
int i, err = 0;
u8 data[2];
struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
@@ -333,26 +231,11 @@ int mt9m111_start(struct sd *sd)
switch (width) {
case 640:
- PDEBUG(D_V4L2, "Configuring camera for VGA mode");
- data[0] = MT9M111_RMB_OVER_SIZED;
- data[1] = MT9M111_RMB_ROW_SKIP_2X |
- MT9M111_RMB_COLUMN_SKIP_2X |
- (sensor_settings[VFLIP_IDX] << 0) |
- (sensor_settings[HFLIP_IDX] << 1);
-
- err = m5602_write_sensor(sd,
- MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ PDEBUG(D_CONF, "Configuring camera for VGA mode");
break;
case 320:
- PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
- data[0] = MT9M111_RMB_OVER_SIZED;
- data[1] = MT9M111_RMB_ROW_SKIP_4X |
- MT9M111_RMB_COLUMN_SKIP_4X |
- (sensor_settings[VFLIP_IDX] << 0) |
- (sensor_settings[HFLIP_IDX] << 1);
- err = m5602_write_sensor(sd,
- MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ PDEBUG(D_CONF, "Configuring camera for QVGA mode");
break;
}
return err;
@@ -361,105 +244,46 @@ int mt9m111_start(struct sd *sd)
void mt9m111_disconnect(struct sd *sd)
{
sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
-static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- int err;
- u8 data[2] = {0x00, 0x00};
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
-
- sensor_settings[VFLIP_IDX] = val;
-
- /* The mt9m111 is flipped by default */
- val = !val;
-
- /* Set the correct page map */
- err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
- if (err < 0)
- return err;
-
- err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
- if (err < 0)
- return err;
-
- data[1] = (data[1] & 0xfe) | val;
- err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
- data, 2);
- return err;
-}
-
-static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
- return 0;
}
-static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ int hflip;
+ int vflip;
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-
- sensor_settings[HFLIP_IDX] = val;
+ PDEBUG(D_CONF, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val);
/* The mt9m111 is flipped by default */
- val = !val;
+ hflip = !sd->hflip->val;
+ vflip = !sd->vflip->val;
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
return err;
- err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
- if (err < 0)
- return err;
-
- data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
+ data[0] = MT9M111_RMB_OVER_SIZED;
+ if (gspca_dev->width == 640) {
+ data[1] = MT9M111_RMB_ROW_SKIP_2X |
+ MT9M111_RMB_COLUMN_SKIP_2X |
+ (hflip << 1) | vflip;
+ } else {
+ data[1] = MT9M111_RMB_ROW_SKIP_4X |
+ MT9M111_RMB_COLUMN_SKIP_4X |
+ (hflip << 1) | vflip;
+ }
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
return err;
}
-static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
-
- return 0;
-}
-
static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
int err;
u8 data[2];
@@ -467,33 +291,19 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
if (err < 0)
return err;
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
- PDEBUG(D_V4L2, "Set auto white balance %d", val);
+ PDEBUG(D_CONF, "Set auto white balance %d", val);
return err;
}
-static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val) {
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read auto white balance %d", *val);
- return 0;
-}
-
static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err, tmp;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[GAIN_IDX] = val;
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -518,7 +328,7 @@ static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
data[1] = (tmp & 0xff);
data[0] = (tmp & 0xff00) >> 8;
- PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
+ PDEBUG(D_CONF, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
data[1], data[0]);
err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
@@ -532,13 +342,11 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[GREEN_BALANCE_IDX] = val;
data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8;
- PDEBUG(D_V4L2, "Set green balance %d", val);
+ PDEBUG(D_CONF, "Set green balance %d", val);
err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
data, 2);
if (err < 0)
@@ -548,66 +356,68 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
data, 2);
}
-static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GREEN_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read green balance %d", *val);
- return 0;
-}
-
static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[BLUE_BALANCE_IDX] = val;
data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8;
- PDEBUG(D_V4L2, "Set blue balance %d", val);
+ PDEBUG(D_CONF, "Set blue balance %d", val);
return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
data, 2);
}
-static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BLUE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read blue balance %d", *val);
- return 0;
-}
-
static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[RED_BALANCE_IDX] = val;
data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8;
- PDEBUG(D_V4L2, "Set red balance %d", val);
+ PDEBUG(D_CONF, "Set red balance %d", val);
return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
data, 2);
}
-static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ int err;
- *val = sensor_settings[RED_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read red balance %d", *val);
- return 0;
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = mt9m111_set_auto_white_balance(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = mt9m111_set_green_balance(gspca_dev, sd->green_bal->val);
+ if (err)
+ return err;
+ err = mt9m111_set_red_balance(gspca_dev, sd->red_bal->val);
+ if (err)
+ return err;
+ err = mt9m111_set_blue_balance(gspca_dev, sd->blue_bal->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = mt9m111_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = mt9m111_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
}
static void mt9m111_dump_registers(struct sd *sd)
diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.h b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
index 8c672b5c8c6..07448d35e3c 100644
--- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
@@ -110,6 +110,7 @@ extern bool dump_sensor;
int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd);
+int mt9m111_init_controls(struct sd *sd);
int mt9m111_start(struct sd *sd);
void mt9m111_disconnect(struct sd *sd);
@@ -121,6 +122,7 @@ static const struct m5602_sensor mt9m111 = {
.probe = mt9m111_probe,
.init = mt9m111_init,
+ .init_controls = mt9m111_init_controls,
.disconnect = mt9m111_disconnect,
.start = mt9m111_start,
};
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
index 9a14835c128..64b3b03a914 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov7660.c
+++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
@@ -20,111 +20,8 @@
#include "m5602_ov7660.h"
-static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-
-static const struct ctrl ov7660_ctrls[] = {
-#define GAIN_IDX 1
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = OV7660_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov7660_set_gain,
- .get = ov7660_get_gain
- },
-#define BLUE_BALANCE_IDX 2
-#define RED_BALANCE_IDX 3
-#define AUTO_WHITE_BALANCE_IDX 4
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov7660_set_auto_white_balance,
- .get = ov7660_get_auto_white_balance
- },
-#define AUTO_GAIN_CTRL_IDX 5
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov7660_set_auto_gain,
- .get = ov7660_get_auto_gain
- },
-#define AUTO_EXPOSURE_IDX 6
- {
- {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov7660_set_auto_exposure,
- .get = ov7660_get_auto_exposure
- },
-#define HFLIP_IDX 7
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov7660_set_hflip,
- .get = ov7660_get_hflip
- },
-#define VFLIP_IDX 8
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov7660_set_vflip,
- .get = ov7660_get_vflip
- },
-
-};
+static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl);
+static void ov7660_dump_registers(struct sd *sd);
static struct v4l2_pix_format ov7660_modes[] = {
{
@@ -140,15 +37,15 @@ static struct v4l2_pix_format ov7660_modes[] = {
}
};
-static void ov7660_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_ops ov7660_ctrl_ops = {
+ .s_ctrl = ov7660_s_ctrl,
+};
int ov7660_probe(struct sd *sd)
{
int err = 0, i;
u8 prod_id = 0, ver_id = 0;
- s32 *sensor_settings;
-
if (force_sensor) {
if (force_sensor == OV7660_SENSOR) {
pr_info("Forcing an %s sensor\n", ov7660.name);
@@ -191,27 +88,15 @@ int ov7660_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = ov7660_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
- sd->desc->ctrls = ov7660_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
- sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
int ov7660_init(struct sd *sd)
{
- int i, err = 0;
- s32 *sensor_settings = sd->sensor_priv;
+ int i, err;
/* Init the sensor */
for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
@@ -226,38 +111,47 @@ int ov7660_init(struct sd *sd)
err = m5602_write_sensor(sd,
init_ov7660[i][1], data, 1);
}
+ if (err < 0)
+ return err;
}
if (dump_sensor)
ov7660_dump_registers(sd);
- err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = ov7660_set_auto_white_balance(&sd->gspca_dev,
- sensor_settings[AUTO_WHITE_BALANCE_IDX]);
- if (err < 0)
- return err;
+int ov7660_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
- err = ov7660_set_auto_gain(&sd->gspca_dev,
- sensor_settings[AUTO_GAIN_CTRL_IDX]);
- if (err < 0)
- return err;
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
- err = ov7660_set_auto_exposure(&sd->gspca_dev,
- sensor_settings[AUTO_EXPOSURE_IDX]);
- if (err < 0)
- return err;
- err = ov7660_set_hflip(&sd->gspca_dev,
- sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
- err = ov7660_set_vflip(&sd->gspca_dev,
- sensor_settings[VFLIP_IDX]);
+ sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0,
+ 255, 1, OV7660_DEFAULT_GAIN);
- return err;
+ sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
+
+ return 0;
}
int ov7660_start(struct sd *sd)
@@ -275,56 +169,29 @@ void ov7660_disconnect(struct sd *sd)
ov7660_stop(sd);
sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
-static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
- return 0;
}
static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
- u8 i2c_data;
+ u8 i2c_data = val;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Setting gain to %d", val);
-
- sensor_settings[GAIN_IDX] = val;
+ PDEBUG(D_CONF, "Setting gain to %d", val);
err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
return err;
}
-
-static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- return 0;
-}
-
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+ PDEBUG(D_CONF, "Set auto white balance to %d", val);
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -335,26 +202,14 @@ static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err;
}
-static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
- PDEBUG(D_V4L2, "Read auto gain control %d", *val);
- return 0;
-}
-
static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto gain control to %d", val);
+ PDEBUG(D_CONF, "Set auto gain control to %d", val);
- sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -364,94 +219,69 @@ static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
}
-static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
- return 0;
-}
-
static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
+ PDEBUG(D_CONF, "Set auto exposure control to %d", val);
- sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0)
return err;
+ val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
}
-static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
- return 0;
-}
-
-static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov7660_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
+ PDEBUG(D_CONF, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val);
- sensor_settings[HFLIP_IDX] = val;
-
- i2c_data = ((val & 0x01) << 5) |
- (sensor_settings[VFLIP_IDX] << 4);
+ i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4);
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
return err;
}
-static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
int err;
- u8 i2c_data;
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- sensor_settings[VFLIP_IDX] = val;
- i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
- err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
- if (err < 0)
- return err;
-
- /* When vflip is toggled we need to readjust the bridge hsync/vsync */
- if (gspca_dev->streaming)
- err = ov7660_start(sd);
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ err = ov7660_set_auto_exposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err = ov7660_set_auto_gain(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = ov7660_set_gain(gspca_dev, sd->gain->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = ov7660_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
return err;
}
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.h b/drivers/media/usb/gspca/m5602/m5602_ov7660.h
index 2b6a13b508f..6fece1ce123 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov7660.h
+++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.h
@@ -90,6 +90,8 @@ extern bool dump_sensor;
int ov7660_probe(struct sd *sd);
int ov7660_init(struct sd *sd);
+int ov7660_init(struct sd *sd);
+int ov7660_init_controls(struct sd *sd);
int ov7660_start(struct sd *sd);
int ov7660_stop(struct sd *sd);
void ov7660_disconnect(struct sd *sd);
@@ -100,6 +102,7 @@ static const struct m5602_sensor ov7660 = {
.i2c_regW = 1,
.probe = ov7660_probe,
.init = ov7660_init,
+ .init_controls = ov7660_init_controls,
.start = ov7660_start,
.stop = ov7660_stop,
.disconnect = ov7660_disconnect,
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.c b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
index 2114a8b90ec..59bc62bfae2 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
@@ -20,26 +20,8 @@
#include "m5602_ov9650.h"
-static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl);
+static void ov9650_dump_registers(struct sd *sd);
/* Vertically and horizontally flips the image if matched, needed for machines
where the sensor is mounted upside down */
@@ -113,140 +95,6 @@ static
{}
};
-static const struct ctrl ov9650_ctrls[] = {
-#define EXPOSURE_IDX 0
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x1ff,
- .step = 0x4,
- .default_value = EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_exposure,
- .get = ov9650_get_exposure
- },
-#define GAIN_IDX 1
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x3ff,
- .step = 0x1,
- .default_value = GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_gain,
- .get = ov9650_get_gain
- },
-#define RED_BALANCE_IDX 2
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_red_balance,
- .get = ov9650_get_red_balance
- },
-#define BLUE_BALANCE_IDX 3
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_blue_balance,
- .get = ov9650_get_blue_balance
- },
-#define HFLIP_IDX 4
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_hflip,
- .get = ov9650_get_hflip
- },
-#define VFLIP_IDX 5
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_vflip,
- .get = ov9650_get_vflip
- },
-#define AUTO_WHITE_BALANCE_IDX 6
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov9650_set_auto_white_balance,
- .get = ov9650_get_auto_white_balance
- },
-#define AUTO_GAIN_CTRL_IDX 7
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov9650_set_auto_gain,
- .get = ov9650_get_auto_gain
- },
-#define AUTO_EXPOSURE_IDX 8
- {
- {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov9650_set_auto_exposure,
- .get = ov9650_get_auto_exposure
- }
-
-};
-
static struct v4l2_pix_format ov9650_modes[] = {
{
176,
@@ -291,13 +139,15 @@ static struct v4l2_pix_format ov9650_modes[] = {
}
};
-static void ov9650_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_ops ov9650_ctrl_ops = {
+ .s_ctrl = ov9650_s_ctrl,
+};
int ov9650_probe(struct sd *sd)
{
int err = 0;
u8 prod_id = 0, ver_id = 0, i;
- s32 *sensor_settings;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == OV9650_SENSOR) {
@@ -338,19 +188,9 @@ int ov9650_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = ov9650_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
- sd->desc->ctrls = ov9650_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
- for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
- sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
@@ -358,7 +198,6 @@ int ov9650_init(struct sd *sd)
{
int i, err = 0;
u8 data;
- s32 *sensor_settings = sd->sensor_priv;
if (dump_sensor)
ov9650_dump_registers(sd);
@@ -372,46 +211,52 @@ int ov9650_init(struct sd *sd)
err = m5602_write_bridge(sd, init_ov9650[i][1], data);
}
- err = ov9650_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_red_balance(&sd->gspca_dev,
- sensor_settings[RED_BALANCE_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_blue_balance(&sd->gspca_dev,
- sensor_settings[BLUE_BALANCE_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = ov9650_set_auto_exposure(&sd->gspca_dev,
- sensor_settings[AUTO_EXPOSURE_IDX]);
- if (err < 0)
- return err;
+int ov9650_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 9);
+
+ sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 255, 1,
+ RED_GAIN_DEFAULT);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 255, 1,
+ BLUE_GAIN_DEFAULT);
+
+ sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
+ sd->expo = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, 0x1ff, 4, EXPOSURE_DEFAULT);
+
+ sd->autogain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ sd->gain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_GAIN, 0,
+ 0x3ff, 1, GAIN_DEFAULT);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
- err = ov9650_set_auto_white_balance(&sd->gspca_dev,
- sensor_settings[AUTO_WHITE_BALANCE_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_auto_cluster(3, &sd->auto_white_bal, 0, false);
+ v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
+ v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
- err = ov9650_set_auto_gain(&sd->gspca_dev,
- sensor_settings[AUTO_GAIN_CTRL_IDX]);
- return err;
+ return 0;
}
int ov9650_start(struct sd *sd)
@@ -419,17 +264,17 @@ int ov9650_start(struct sd *sd)
u8 data;
int i, err = 0;
struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
int hor_offs = OV9650_LEFT_OFFSET;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if ((!dmi_check_system(ov9650_flip_dmi_table) &&
- sensor_settings[VFLIP_IDX]) ||
+ sd->vflip->val) ||
(dmi_check_system(ov9650_flip_dmi_table) &&
- !sensor_settings[VFLIP_IDX]))
+ !sd->vflip->val))
ver_offs--;
if (width <= 320)
@@ -508,7 +353,7 @@ int ov9650_start(struct sd *sd)
switch (width) {
case 640:
- PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+ PDEBUG(D_CONF, "Configuring camera for VGA mode");
data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -516,7 +361,7 @@ int ov9650_start(struct sd *sd)
break;
case 352:
- PDEBUG(D_V4L2, "Configuring camera for CIF mode");
+ PDEBUG(D_CONF, "Configuring camera for CIF mode");
data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -524,7 +369,7 @@ int ov9650_start(struct sd *sd)
break;
case 320:
- PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
+ PDEBUG(D_CONF, "Configuring camera for QVGA mode");
data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -532,7 +377,7 @@ int ov9650_start(struct sd *sd)
break;
case 176:
- PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
+ PDEBUG(D_CONF, "Configuring camera for QCIF mode");
data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -553,29 +398,16 @@ void ov9650_disconnect(struct sd *sd)
ov9650_stop(sd);
sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
-static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read exposure %d", *val);
- return 0;
}
static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- PDEBUG(D_V4L2, "Set exposure to %d", val);
+ PDEBUG(D_CONF, "Set exposure to %d", val);
- sensor_settings[EXPOSURE_IDX] = val;
/* The 6 MSBs */
i2c_data = (val >> 10) & 0x3f;
err = m5602_write_sensor(sd, OV9650_AECHM,
@@ -596,26 +428,13 @@ static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
- return 0;
-}
-
static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Setting gain to %d", val);
-
- sensor_settings[GAIN_IDX] = val;
+ PDEBUG(D_CONF, "Setting gain to %d", val);
/* The 2 MSB */
/* Read the OV9650_VREF register first to avoid
@@ -637,117 +456,46 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[RED_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read red gain %d", *val);
- return 0;
-}
-
static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set red gain to %d", val);
-
- sensor_settings[RED_BALANCE_IDX] = val;
+ PDEBUG(D_CONF, "Set red gain to %d", val);
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
return err;
}
-static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BLUE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read blue gain %d", *val);
-
- return 0;
-}
-
static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set blue gain to %d", val);
- sensor_settings[BLUE_BALANCE_IDX] = val;
+ PDEBUG(D_CONF, "Set blue gain to %d", val);
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
return err;
}
-static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
- return 0;
-}
-
-static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ int hflip = sd->hflip->val;
+ int vflip = sd->vflip->val;
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-
- sensor_settings[HFLIP_IDX] = val;
-
- if (!dmi_check_system(ov9650_flip_dmi_table))
- i2c_data = ((val & 0x01) << 5) |
- (sensor_settings[VFLIP_IDX] << 4);
- else
- i2c_data = ((val & 0x01) << 5) |
- (!sensor_settings[VFLIP_IDX] << 4);
-
- err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
-
- return err;
-}
-
-static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- int err;
- u8 i2c_data;
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- sensor_settings[VFLIP_IDX] = val;
+ PDEBUG(D_CONF, "Set hvflip to %d %d", hflip, vflip);
if (dmi_check_system(ov9650_flip_dmi_table))
- val = !val;
+ vflip = !vflip;
- i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
+ i2c_data = (hflip << 5) | (vflip << 4);
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0)
return err;
@@ -759,57 +507,34 @@ static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
- return 0;
-}
-
static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
+ PDEBUG(D_CONF, "Set auto exposure control to %d", val);
- sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
return err;
+ val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
}
-static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- return 0;
-}
-
static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+ PDEBUG(D_CONF, "Set auto white balance to %d", val);
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -820,26 +545,14 @@ static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err;
}
-static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
- PDEBUG(D_V4L2, "Read auto gain control %d", *val);
- return 0;
-}
-
static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto gain control to %d", val);
+ PDEBUG(D_CONF, "Set auto gain control to %d", val);
- sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -849,6 +562,48 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
}
+static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = ov9650_set_auto_white_balance(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = ov9650_set_red_balance(gspca_dev, sd->red_bal->val);
+ if (err)
+ return err;
+ err = ov9650_set_blue_balance(gspca_dev, sd->blue_bal->val);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ err = ov9650_set_auto_exposure(gspca_dev, ctrl->val);
+ if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
+ return err;
+ err = ov9650_set_exposure(gspca_dev, sd->expo->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err = ov9650_set_auto_gain(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = ov9650_set_gain(gspca_dev, sd->gain->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = ov9650_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
static void ov9650_dump_registers(struct sd *sd)
{
int address;
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.h b/drivers/media/usb/gspca/m5602/m5602_ov9650.h
index f7aa5bf6898..f9f5870da60 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.h
@@ -139,6 +139,7 @@ extern bool dump_sensor;
int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
+int ov9650_init_controls(struct sd *sd);
int ov9650_start(struct sd *sd);
int ov9650_stop(struct sd *sd);
void ov9650_disconnect(struct sd *sd);
@@ -149,6 +150,7 @@ static const struct m5602_sensor ov9650 = {
.i2c_regW = 1,
.probe = ov9650_probe,
.init = ov9650_init,
+ .init_controls = ov9650_init_controls,
.start = ov9650_start,
.stop = ov9650_stop,
.disconnect = ov9650_disconnect,
diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c
index b8771698cbc..4bf5c43424b 100644
--- a/drivers/media/usb/gspca/m5602/m5602_po1030.c
+++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c
@@ -20,28 +20,8 @@
#include "m5602_po1030.h"
-static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
- __s32 val);
-static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
- __s32 *val);
+static int po1030_s_ctrl(struct v4l2_ctrl *ctrl);
+static void po1030_dump_registers(struct sd *sd);
static struct v4l2_pix_format po1030_modes[] = {
{
@@ -56,146 +36,26 @@ static struct v4l2_pix_format po1030_modes[] = {
}
};
-static const struct ctrl po1030_ctrls[] = {
-#define GAIN_IDX 0
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x4f,
- .step = 0x1,
- .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_gain,
- .get = po1030_get_gain
- },
-#define EXPOSURE_IDX 1
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x02ff,
- .step = 0x1,
- .default_value = PO1030_EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_exposure,
- .get = po1030_get_exposure
- },
-#define RED_BALANCE_IDX 2
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_red_balance,
- .get = po1030_get_red_balance
- },
-#define BLUE_BALANCE_IDX 3
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_blue_balance,
- .get = po1030_get_blue_balance
- },
-#define HFLIP_IDX 4
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_hflip,
- .get = po1030_get_hflip
- },
-#define VFLIP_IDX 5
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_vflip,
- .get = po1030_get_vflip
- },
-#define AUTO_WHITE_BALANCE_IDX 6
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_auto_white_balance,
- .get = po1030_get_auto_white_balance
- },
-#define AUTO_EXPOSURE_IDX 7
- {
- {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_auto_exposure,
- .get = po1030_get_auto_exposure
- },
-#define GREEN_BALANCE_IDX 8
- {
- {
- .id = M5602_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_GREEN_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_green_balance,
- .get = po1030_get_green_balance
- },
+static const struct v4l2_ctrl_ops po1030_ctrl_ops = {
+ .s_ctrl = po1030_s_ctrl,
};
-static void po1030_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_config po1030_greenbal_cfg = {
+ .ops = &po1030_ctrl_ops,
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .name = "Green Balance",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 255,
+ .step = 1,
+ .def = PO1030_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+};
int po1030_probe(struct sd *sd)
{
u8 dev_id_h = 0, i;
- s32 *sensor_settings;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == PO1030_SENSOR) {
@@ -229,26 +89,14 @@ int po1030_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = po1030_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
- sd->desc->ctrls = po1030_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
- sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
int po1030_init(struct sd *sd)
{
- s32 *sensor_settings = sd->sensor_priv;
int i, err = 0;
/* Init the sensor */
@@ -279,46 +127,50 @@ int po1030_init(struct sd *sd)
if (dump_sensor)
po1030_dump_registers(sd);
- err = po1030_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_red_balance(&sd->gspca_dev,
- sensor_settings[RED_BALANCE_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_blue_balance(&sd->gspca_dev,
- sensor_settings[BLUE_BALANCE_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = po1030_set_green_balance(&sd->gspca_dev,
- sensor_settings[GREEN_BALANCE_IDX]);
- if (err < 0)
- return err;
+int po1030_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 9);
+
+ sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 0);
+ sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 255, 1,
+ PO1030_RED_GAIN_DEFAULT);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 255, 1,
+ PO1030_BLUE_GAIN_DEFAULT);
+
+ sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL);
+ sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT);
+
+ sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0,
+ 0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
- err = po1030_set_auto_white_balance(&sd->gspca_dev,
- sensor_settings[AUTO_WHITE_BALANCE_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
+ v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
- err = po1030_set_auto_exposure(&sd->gspca_dev,
- sensor_settings[AUTO_EXPOSURE_IDX]);
- return err;
+ return 0;
}
int po1030_start(struct sd *sd)
@@ -448,28 +300,16 @@ int po1030_start(struct sd *sd)
return err;
}
-static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Exposure read as %d", *val);
- return 0;
-}
-
static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[EXPOSURE_IDX] = val;
- PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
+ PDEBUG(D_CONF, "Set exposure to %d", val & 0xffff);
i2c_data = ((val & 0xff00) >> 8);
- PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
+ PDEBUG(D_CONF, "Set exposure to high byte to 0x%x",
i2c_data);
err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
@@ -478,7 +318,7 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
i2c_data = (val & 0xff);
- PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
+ PDEBUG(D_CONF, "Set exposure to low byte to 0x%x",
i2c_data);
err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
&i2c_data, 1);
@@ -486,91 +326,32 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read global gain %d", *val);
- return 0;
-}
-
static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[GAIN_IDX] = val;
-
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set global gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
&i2c_data, 1);
return err;
}
-static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read hflip %d", *val);
-
- return 0;
-}
-
-static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- u8 i2c_data;
- int err;
-
- sensor_settings[HFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set hflip %d", val);
- err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
- if (err < 0)
- return err;
-
- i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
-
- err = m5602_write_sensor(sd, PO1030_CONTROL2,
- &i2c_data, 1);
-
- return err;
-}
-
-static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_set_hvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vflip %d", *val);
-
- return 0;
-}
-
-static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[VFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set vflip %d", val);
+ PDEBUG(D_CONF, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val);
err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
if (err < 0)
return err;
- i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
+ i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) |
+ (sd->vflip->val << 6);
err = m5602_write_sensor(sd, PO1030_CONTROL2,
&i2c_data, 1);
@@ -578,81 +359,41 @@ static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[RED_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read red gain %d", *val);
- return 0;
-}
-
static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[RED_BALANCE_IDX] = val;
-
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set red gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_RED_GAIN,
&i2c_data, 1);
return err;
}
-static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BLUE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read blue gain %d", *val);
-
- return 0;
-}
-
static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[BLUE_BALANCE_IDX] = val;
-
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set blue gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
&i2c_data, 1);
return err;
}
-static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GREEN_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read green gain %d", *val);
-
- return 0;
-}
-
static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[GREEN_BALANCE_IDX] = val;
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set green gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
&i2c_data, 1);
@@ -663,63 +404,36 @@ static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
&i2c_data, 1);
}
-static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
-
- return 0;
-}
-
static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
-
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
if (err < 0)
return err;
- PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+ PDEBUG(D_CONF, "Set auto white balance to %d", val);
i2c_data = (i2c_data & 0xfe) | (val & 0x01);
err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
return err;
}
-static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Auto exposure is %d", *val);
- return 0;
-}
-
static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
if (err < 0)
return err;
- PDEBUG(D_V4L2, "Set auto exposure to %d", val);
+ PDEBUG(D_CONF, "Set auto exposure to %d", val);
+ val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
}
@@ -727,7 +441,48 @@ static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
void po1030_disconnect(struct sd *sd)
{
sd->sensor = NULL;
- kfree(sd->sensor_priv);
+}
+
+static int po1030_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = po1030_set_auto_white_balance(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = po1030_set_green_balance(gspca_dev, sd->green_bal->val);
+ if (err)
+ return err;
+ err = po1030_set_red_balance(gspca_dev, sd->red_bal->val);
+ if (err)
+ return err;
+ err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ err = po1030_set_auto_exposure(gspca_dev, ctrl->val);
+ if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
+ return err;
+ err = po1030_set_exposure(gspca_dev, sd->expo->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = po1030_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = po1030_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
}
static void po1030_dump_registers(struct sd *sd)
diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.h b/drivers/media/usb/gspca/m5602/m5602_po1030.h
index 81a2bcb88fe..a6ab76149bd 100644
--- a/drivers/media/usb/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/usb/gspca/m5602/m5602_po1030.h
@@ -151,6 +151,7 @@ extern bool dump_sensor;
int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd);
+int po1030_init_controls(struct sd *sd);
int po1030_start(struct sd *sd);
void po1030_disconnect(struct sd *sd);
@@ -162,6 +163,7 @@ static const struct m5602_sensor po1030 = {
.probe = po1030_probe,
.init = po1030_init,
+ .init_controls = po1030_init_controls,
.start = po1030_start,
.disconnect = po1030_disconnect,
};
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
index c8e1572eb50..7d12599458e 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
@@ -20,18 +20,12 @@
#include "m5602_s5k4aa.h"
-static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
+static void s5k4aa_dump_registers(struct sd *sd);
+
+static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
+ .s_ctrl = s5k4aa_s_ctrl,
+};
static
const
@@ -147,104 +141,12 @@ static struct v4l2_pix_format s5k4aa_modes[] = {
}
};
-static const struct ctrl s5k4aa_ctrls[] = {
-#define VFLIP_IDX 0
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_vflip,
- .get = s5k4aa_get_vflip
- },
-#define HFLIP_IDX 1
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_hflip,
- .get = s5k4aa_get_hflip
- },
-#define GAIN_IDX 2
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = S5K4AA_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_gain,
- .get = s5k4aa_get_gain
- },
-#define EXPOSURE_IDX 3
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 13,
- .maximum = 0xfff,
- .step = 1,
- .default_value = 0x100,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_exposure,
- .get = s5k4aa_get_exposure
- },
-#define NOISE_SUPP_IDX 4
- {
- {
- .id = V4L2_CID_PRIVATE_BASE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Noise suppression (smoothing)",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- .set = s5k4aa_set_noise,
- .get = s5k4aa_get_noise
- },
-#define BRIGHTNESS_IDX 5
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 0x1f,
- .step = 1,
- .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
- },
- .set = s5k4aa_set_brightness,
- .get = s5k4aa_get_brightness
- },
-
-};
-
-static void s5k4aa_dump_registers(struct sd *sd);
-
int s5k4aa_probe(struct sd *sd)
{
u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int i, err = 0;
- s32 *sensor_settings;
if (force_sensor) {
if (force_sensor == S5K4AA_SENSOR) {
@@ -303,19 +205,8 @@ int s5k4aa_probe(struct sd *sd)
pr_info("Detected a s5k4aa sensor\n");
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
- sd->desc->ctrls = s5k4aa_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
- sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
@@ -325,11 +216,11 @@ int s5k4aa_start(struct sd *sd)
int i, err = 0;
u8 data[2];
struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
case 1280:
- PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
+ PDEBUG(D_CONF, "Configuring camera for SXGA mode");
for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
switch (SXGA_s5k4aa[i][0]) {
@@ -359,13 +250,10 @@ int s5k4aa_start(struct sd *sd)
return -EINVAL;
}
}
- err = s5k4aa_set_noise(&sd->gspca_dev, 0);
- if (err < 0)
- return err;
break;
case 640:
- PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+ PDEBUG(D_CONF, "Configuring camera for VGA mode");
for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
switch (VGA_s5k4aa[i][0]) {
@@ -395,37 +283,12 @@ int s5k4aa_start(struct sd *sd)
return -EINVAL;
}
}
- err = s5k4aa_set_noise(&sd->gspca_dev, 1);
- if (err < 0)
- return err;
break;
}
if (err < 0)
return err;
- err = s5k4aa_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_brightness(&sd->gspca_dev,
- sensor_settings[BRIGHTNESS_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
-
- return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+ return 0;
}
int s5k4aa_init(struct sd *sd)
@@ -466,13 +329,36 @@ int s5k4aa_init(struct sd *sd)
return err;
}
-static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+int s5k4aa_init_controls(struct sd *sd)
{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
- *val = sensor_settings[EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read exposure %d", *val);
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
+
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
+ 13, 0xfff, 1, 0x100);
+
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
+ 0, 127, 1, S5K4AA_DEFAULT_GAIN);
+
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
+ 0, 1, 1, 1);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->hflip);
return 0;
}
@@ -480,12 +366,10 @@ static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[EXPOSURE_IDX] = val;
- PDEBUG(D_V4L2, "Set exposure to %d", val);
+ PDEBUG(D_CONF, "Set exposure to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -499,27 +383,15 @@ static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
+ int hflip = sd->hflip->val;
+ int vflip = sd->vflip->val;
- sensor_settings[VFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
+ PDEBUG(D_CONF, "Set hvflip %d %d", hflip, vflip);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -528,93 +400,48 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
if (err < 0)
return err;
- if (dmi_check_system(s5k4aa_vflip_dmi_table))
- val = !val;
+ if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
+ hflip = !hflip;
+ vflip = !vflip;
+ }
- data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
+ data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
return err;
- err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
return err;
- if (val)
+ if (hflip)
data &= 0xfe;
else
data |= 0x01;
- err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- return err;
-}
-
-static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
- return 0;
-}
-
-static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- u8 data = S5K4AA_PAGE_MAP_2;
- int err;
-
- sensor_settings[HFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
- err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- if (err < 0)
- return err;
-
- err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
- if (err < 0)
- return err;
-
- if (dmi_check_system(s5k4aa_vflip_dmi_table))
- val = !val;
-
- data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
- err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
return err;
- err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
return err;
- if (val)
+ if (vflip)
data &= 0xfe;
else
data |= 0x01;
- err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
- return err;
-}
-
-static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ if (err < 0)
+ return err;
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
return 0;
}
static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[GAIN_IDX] = val;
-
- PDEBUG(D_V4L2, "Set gain to %d", val);
+ PDEBUG(D_CONF, "Set gain to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -625,26 +452,13 @@ static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BRIGHTNESS_IDX];
- PDEBUG(D_V4L2, "Read brightness %d", *val);
- return 0;
-}
-
static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[BRIGHTNESS_IDX] = val;
-
- PDEBUG(D_V4L2, "Set brightness to %d", val);
+ PDEBUG(D_CONF, "Set brightness to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -653,26 +467,13 @@ static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
}
-static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[NOISE_SUPP_IDX];
- PDEBUG(D_V4L2, "Read noise %d", *val);
- return 0;
-}
-
static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[NOISE_SUPP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set noise to %d", val);
+ PDEBUG(D_CONF, "Set noise to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -681,10 +482,41 @@ static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
}
+static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ int err;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = s5k4aa_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ err = s5k4aa_set_noise(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = s5k4aa_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
void s5k4aa_disconnect(struct sd *sd)
{
sd->sensor = NULL;
- kfree(sd->sensor_priv);
}
static void s5k4aa_dump_registers(struct sd *sd)
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
index 8e0035e731c..9953e976695 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
@@ -69,6 +69,7 @@ extern bool dump_sensor;
int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
+int s5k4aa_init_controls(struct sd *sd);
int s5k4aa_start(struct sd *sd);
void s5k4aa_disconnect(struct sd *sd);
@@ -79,6 +80,7 @@ static const struct m5602_sensor s5k4aa = {
.probe = s5k4aa_probe,
.init = s5k4aa_init,
+ .init_controls = s5k4aa_init_controls,
.start = s5k4aa_start,
.disconnect = s5k4aa_disconnect,
};
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
index 1de743a02b0..7cbc3a00bda 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
@@ -21,16 +21,11 @@
#include <linux/kthread.h>
#include "m5602_s5k83a.h"
-static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
+ .s_ctrl = s5k83a_s_ctrl,
+};
static struct v4l2_pix_format s5k83a_modes[] = {
{
@@ -46,83 +41,6 @@ static struct v4l2_pix_format s5k83a_modes[] = {
}
};
-static const struct ctrl s5k83a_ctrls[] = {
-#define GAIN_IDX 0
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_gain,
- .get = s5k83a_get_gain
-
- },
-#define BRIGHTNESS_IDX 1
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_BRIGHTNESS,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_brightness,
- .get = s5k83a_get_brightness,
- },
-#define EXPOSURE_IDX 2
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = S5K83A_MAXIMUM_EXPOSURE,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_EXPOSURE,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_exposure,
- .get = s5k83a_get_exposure
- },
-#define HFLIP_IDX 3
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_hflip,
- .get = s5k83a_get_hflip
- },
-#define VFLIP_IDX 4
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_vflip,
- .get = s5k83a_get_vflip
- }
-};
-
static void s5k83a_dump_registers(struct sd *sd);
static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
static int s5k83a_set_led_indication(struct sd *sd, u8 val);
@@ -131,9 +49,9 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
int s5k83a_probe(struct sd *sd)
{
- struct s5k83a_priv *sens_priv;
u8 prod_id = 0, ver_id = 0;
int i, err = 0;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == S5K83A_SENSOR) {
@@ -173,38 +91,18 @@ int s5k83a_probe(struct sd *sd)
pr_info("Detected a s5k83a sensor\n");
sensor_found:
- sens_priv = kmalloc(
- sizeof(struct s5k83a_priv), GFP_KERNEL);
- if (!sens_priv)
- return -ENOMEM;
-
- sens_priv->settings =
- kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
- if (!sens_priv->settings) {
- kfree(sens_priv);
- return -ENOMEM;
- }
-
sd->gspca_dev.cam.cam_mode = s5k83a_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
- sd->desc->ctrls = s5k83a_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
/* null the pointer! thread is't running now */
- sens_priv->rotation_thread = NULL;
-
- for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
- sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
+ sd->rotation_thread = NULL;
- sd->sensor_priv = sens_priv;
return 0;
}
int s5k83a_init(struct sd *sd)
{
int i, err = 0;
- s32 *sensor_settings =
- ((struct s5k83a_priv *) sd->sensor_priv)->settings;
for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
u8 data[2] = {0x00, 0x00};
@@ -237,33 +135,44 @@ int s5k83a_init(struct sd *sd)
if (dump_sensor)
s5k83a_dump_registers(sd);
- err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
+ return err;
+}
- err = s5k83a_set_brightness(&sd->gspca_dev,
- sensor_settings[BRIGHTNESS_IDX]);
- if (err < 0)
- return err;
+int s5k83a_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
- err = s5k83a_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
- err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ 0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
- err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+ v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, S5K83A_MAXIMUM_EXPOSURE, 1,
+ S5K83A_DEFAULT_EXPOSURE);
- return err;
+ v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
+ 0, 255, 1, S5K83A_DEFAULT_GAIN);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->hflip);
+
+ return 0;
}
static int rotation_thread_function(void *data)
{
struct sd *sd = (struct sd *) data;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
u8 reg, previous_rotation = 0;
__s32 vflip, hflip;
@@ -277,8 +186,8 @@ static int rotation_thread_function(void *data)
previous_rotation = reg;
pr_info("Camera was flipped\n");
- s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
- s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+ hflip = sd->hflip->val;
+ vflip = sd->vflip->val;
if (reg) {
vflip = !vflip;
@@ -294,26 +203,25 @@ static int rotation_thread_function(void *data)
/* return to "front" flip */
if (previous_rotation) {
- s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
- s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+ hflip = sd->hflip->val;
+ vflip = sd->vflip->val;
s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
}
- sens_priv->rotation_thread = NULL;
+ sd->rotation_thread = NULL;
return 0;
}
int s5k83a_start(struct sd *sd)
{
int i, err = 0;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
/* Create another thread, polling the GPIO ports of the camera to check
if it got rotated. This is how the windows driver does it so we have
to assume that there is no better way of accomplishing this */
- sens_priv->rotation_thread = kthread_create(rotation_thread_function,
- sd, "rotation thread");
- wake_up_process(sens_priv->rotation_thread);
+ sd->rotation_thread = kthread_create(rotation_thread_function,
+ sd, "rotation thread");
+ wake_up_process(sd->rotation_thread);
/* Preinit the sensor */
for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
@@ -333,32 +241,17 @@ int s5k83a_start(struct sd *sd)
int s5k83a_stop(struct sd *sd)
{
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- if (sens_priv->rotation_thread)
- kthread_stop(sens_priv->rotation_thread);
+ if (sd->rotation_thread)
+ kthread_stop(sd->rotation_thread);
return s5k83a_set_led_indication(sd, 0);
}
void s5k83a_disconnect(struct sd *sd)
{
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
s5k83a_stop(sd);
sd->sensor = NULL;
- kfree(sens_priv->settings);
- kfree(sens_priv);
-}
-
-static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[GAIN_IDX];
- return 0;
}
static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -366,9 +259,6 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- sens_priv->settings[GAIN_IDX] = val;
data[0] = 0x00;
data[1] = 0x20;
@@ -391,60 +281,29 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[BRIGHTNESS_IDX];
- return 0;
-}
-
static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[1];
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
- sens_priv->settings[BRIGHTNESS_IDX] = val;
data[0] = val;
err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
return err;
}
-static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[EXPOSURE_IDX];
- return 0;
-}
-
static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
- sens_priv->settings[EXPOSURE_IDX] = val;
data[0] = 0;
data[1] = val;
err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
return err;
}
-static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[VFLIP_IDX];
- return 0;
-}
-
static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
__s32 vflip, __s32 hflip)
{
@@ -476,60 +335,52 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
return err;
}
-static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 reg;
- __s32 hflip;
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- sens_priv->settings[VFLIP_IDX] = val;
-
- s5k83a_get_hflip(gspca_dev, &hflip);
+ int hflip = sd->hflip->val;
+ int vflip = sd->vflip->val;
err = s5k83a_get_rotation(sd, &reg);
if (err < 0)
return err;
if (reg) {
- val = !val;
hflip = !hflip;
+ vflip = !vflip;
}
- err = s5k83a_set_flip_real(gspca_dev, val, hflip);
+ err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
return err;
}
-static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[HFLIP_IDX];
- return 0;
-}
-
-static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
int err;
- u8 reg;
- __s32 vflip;
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- sens_priv->settings[HFLIP_IDX] = val;
- s5k83a_get_vflip(gspca_dev, &vflip);
-
- err = s5k83a_get_rotation(sd, &reg);
- if (err < 0)
- return err;
- if (reg) {
- val = !val;
- vflip = !vflip;
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ err = s5k83a_set_brightness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ err = s5k83a_set_exposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = s5k83a_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = s5k83a_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
}
- err = s5k83a_set_flip_real(gspca_dev, vflip, val);
return err;
}
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.h b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
index 79952247b53..d61b918228d 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
@@ -45,6 +45,7 @@ extern bool dump_sensor;
int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
+int s5k83a_init_controls(struct sd *sd);
int s5k83a_start(struct sd *sd);
int s5k83a_stop(struct sd *sd);
void s5k83a_disconnect(struct sd *sd);
@@ -53,6 +54,7 @@ static const struct m5602_sensor s5k83a = {
.name = "S5K83A",
.probe = s5k83a_probe,
.init = s5k83a_init,
+ .init_controls = s5k83a_init_controls,
.start = s5k83a_start,
.stop = s5k83a_stop,
.disconnect = s5k83a_disconnect,
@@ -60,13 +62,6 @@ static const struct m5602_sensor s5k83a = {
.i2c_regW = 2,
};
-struct s5k83a_priv {
- /* We use another thread periodically
- probing the orientation of the camera */
- struct task_struct *rotation_thread;
- s32 *settings;
-};
-
static const unsigned char preinit_s5k83a[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
diff --git a/drivers/media/usb/gspca/m5602/m5602_sensor.h b/drivers/media/usb/gspca/m5602/m5602_sensor.h
index edff4f1f586..48341b4d607 100644
--- a/drivers/media/usb/gspca/m5602/m5602_sensor.h
+++ b/drivers/media/usb/gspca/m5602/m5602_sensor.h
@@ -57,6 +57,9 @@ struct m5602_sensor {
/* Performs a initialization sequence */
int (*init)(struct sd *sd);
+ /* Controls initialization, maybe NULL */
+ int (*init_controls)(struct sd *sd);
+
/* Executed when the camera starts to send data */
int (*start)(struct sd *sd);
diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c
index 8f4714df599..68bb2f35966 100644
--- a/drivers/media/usb/gspca/mr97310a.c
+++ b/drivers/media/usb/gspca/mr97310a.c
@@ -289,7 +289,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
return err_code;
}
if (status != 0x0a)
- PDEBUG(D_ERR, "status is %02x", status);
+ PERR("status is %02x", status);
tries = 0;
while (tries < 4) {
@@ -330,7 +330,7 @@ static void stream_stop(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0] = 0x01;
gspca_dev->usb_buf[1] = 0x00;
if (mr_write(gspca_dev, 2) < 0)
- PDEBUG(D_ERR, "Stream Stop failed");
+ PERR("Stream Stop failed");
}
static void lcd_stop(struct gspca_dev *gspca_dev)
@@ -338,7 +338,7 @@ static void lcd_stop(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0] = 0x19;
gspca_dev->usb_buf[1] = 0x54;
if (mr_write(gspca_dev, 2) < 0)
- PDEBUG(D_ERR, "LCD Stop failed");
+ PERR("LCD Stop failed");
}
static int isoc_enable(struct gspca_dev *gspca_dev)
@@ -1026,7 +1026,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
unsigned char *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n;
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index 9ad19a7ef81..a3958ee8681 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -2034,6 +2034,7 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
/* Write a OV519 register */
static void reg_w(struct sd *sd, u16 index, u16 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret, req = 0;
if (sd->gspca_dev.usb_err < 0)
@@ -2071,7 +2072,7 @@ static void reg_w(struct sd *sd, u16 index, u16 value)
sd->gspca_dev.usb_buf, 1, 500);
leave:
if (ret < 0) {
- pr_err("reg_w %02x failed %d\n", index, ret);
+ PERR("reg_w %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
return;
}
@@ -2081,6 +2082,7 @@ leave:
/* returns: negative is error, pos or zero is data */
static int reg_r(struct sd *sd, u16 index)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
int req;
@@ -2110,7 +2112,7 @@ static int reg_r(struct sd *sd, u16 index)
PDEBUG(D_USBI, "GET %02x 0000 %04x %02x",
req, index, ret);
} else {
- pr_err("reg_r %02x failed %d\n", index, ret);
+ PERR("reg_r %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2121,6 +2123,7 @@ static int reg_r(struct sd *sd, u16 index)
static int reg_r8(struct sd *sd,
u16 index)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2135,7 +2138,7 @@ static int reg_r8(struct sd *sd,
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
} else {
- pr_err("reg_r8 %02x failed %d\n", index, ret);
+ PERR("reg_r8 %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2174,6 +2177,7 @@ static void reg_w_mask(struct sd *sd,
*/
static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2188,13 +2192,14 @@ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
0, index,
sd->gspca_dev.usb_buf, n, 500);
if (ret < 0) {
- pr_err("reg_w32 %02x failed %d\n", index, ret);
+ PERR("reg_w32 %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
}
}
static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc, retries;
PDEBUG(D_USBO, "ov511_i2c_w %02x %02x", reg, value);
@@ -2228,6 +2233,7 @@ static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value)
static int ov511_i2c_r(struct sd *sd, u8 reg)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc, value, retries;
/* Two byte write cycle */
@@ -2300,6 +2306,8 @@ static void ov518_i2c_w(struct sd *sd,
u8 reg,
u8 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_USBO, "ov518_i2c_w %02x %02x", reg, value);
/* Select camera register */
@@ -2325,6 +2333,7 @@ static void ov518_i2c_w(struct sd *sd,
*/
static int ov518_i2c_r(struct sd *sd, u8 reg)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int value;
/* Select camera register */
@@ -2345,6 +2354,7 @@ static int ov518_i2c_r(struct sd *sd, u8 reg)
static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2357,7 +2367,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
(u16) value, (u16) reg, NULL, 0, 500);
if (ret < 0) {
- pr_err("ovfx2_i2c_w %02x failed %d\n", reg, ret);
+ PERR("ovfx2_i2c_w %02x failed %d\n", reg, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2366,6 +2376,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
static int ovfx2_i2c_r(struct sd *sd, u8 reg)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2381,7 +2392,7 @@ static int ovfx2_i2c_r(struct sd *sd, u8 reg)
ret = sd->gspca_dev.usb_buf[0];
PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret);
} else {
- pr_err("ovfx2_i2c_r %02x failed %d\n", reg, ret);
+ PERR("ovfx2_i2c_r %02x failed %d\n", reg, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2478,6 +2489,8 @@ static void i2c_w_mask(struct sd *sd,
* registers while the camera is streaming */
static inline void ov51x_stop(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_STREAM, "stopping");
sd->stopped = 1;
switch (sd->bridge) {
@@ -2507,6 +2520,8 @@ static inline void ov51x_stop(struct sd *sd)
* actually stopped (for performance). */
static inline void ov51x_restart(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_STREAM, "restarting");
if (!sd->stopped)
return;
@@ -2545,6 +2560,7 @@ static void ov51x_set_slave_ids(struct sd *sd, u8 slave);
static int init_ov_sensor(struct sd *sd, u8 slave)
{
int i;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
ov51x_set_slave_ids(sd, slave);
@@ -2624,10 +2640,11 @@ static void write_i2c_regvals(struct sd *sd,
/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */
static void ov_hires_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int high, low;
if (sd->bridge != BRIDGE_OVFX2) {
- pr_err("error hires sensors only supported with ovfx2\n");
+ PERR("error hires sensors only supported with ovfx2\n");
return;
}
@@ -2662,7 +2679,7 @@ static void ov_hires_configure(struct sd *sd)
}
break;
}
- pr_err("Error unknown sensor type: %02x%02x\n", high, low);
+ PERR("Error unknown sensor type: %02x%02x\n", high, low);
}
/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
@@ -2670,6 +2687,7 @@ static void ov_hires_configure(struct sd *sd)
*/
static void ov8xx0_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc;
PDEBUG(D_PROBE, "starting ov8xx0 configuration");
@@ -2677,13 +2695,13 @@ static void ov8xx0_configure(struct sd *sd)
/* Detect sensor (sub)type */
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
- PDEBUG(D_ERR, "Error detecting sensor type");
+ PERR("Error detecting sensor type");
return;
}
if ((rc & 3) == 1)
sd->sensor = SEN_OV8610;
else
- pr_err("Unknown image sensor version: %d\n", rc & 3);
+ PERR("Unknown image sensor version: %d\n", rc & 3);
}
/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
@@ -2691,6 +2709,7 @@ static void ov8xx0_configure(struct sd *sd)
*/
static void ov7xx0_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc, high, low;
PDEBUG(D_PROBE, "starting OV7xx0 configuration");
@@ -2701,7 +2720,7 @@ static void ov7xx0_configure(struct sd *sd)
/* add OV7670 here
* it appears to be wrongly detected as a 7610 by default */
if (rc < 0) {
- pr_err("Error detecting sensor type\n");
+ PERR("Error detecting sensor type\n");
return;
}
if ((rc & 3) == 3) {
@@ -2729,19 +2748,19 @@ static void ov7xx0_configure(struct sd *sd)
/* try to read product id registers */
high = i2c_r(sd, 0x0a);
if (high < 0) {
- pr_err("Error detecting camera chip PID\n");
+ PERR("Error detecting camera chip PID\n");
return;
}
low = i2c_r(sd, 0x0b);
if (low < 0) {
- pr_err("Error detecting camera chip VER\n");
+ PERR("Error detecting camera chip VER\n");
return;
}
if (high == 0x76) {
switch (low) {
case 0x30:
- pr_err("Sensor is an OV7630/OV7635\n");
- pr_err("7630 is not supported by this driver\n");
+ PERR("Sensor is an OV7630/OV7635\n");
+ PERR("7630 is not supported by this driver\n");
return;
case 0x40:
PDEBUG(D_PROBE, "Sensor is an OV7645");
@@ -2760,7 +2779,7 @@ static void ov7xx0_configure(struct sd *sd)
sd->sensor = SEN_OV7660;
break;
default:
- pr_err("Unknown sensor: 0x76%02x\n", low);
+ PERR("Unknown sensor: 0x76%02x\n", low);
return;
}
} else {
@@ -2768,20 +2787,22 @@ static void ov7xx0_configure(struct sd *sd)
sd->sensor = SEN_OV7620;
}
} else {
- pr_err("Unknown image sensor version: %d\n", rc & 3);
+ PERR("Unknown image sensor version: %d\n", rc & 3);
}
}
/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
static void ov6xx0_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc;
+
PDEBUG(D_PROBE, "starting OV6xx0 configuration");
/* Detect sensor (sub)type */
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
- pr_err("Error detecting sensor type\n");
+ PERR("Error detecting sensor type\n");
return;
}
@@ -2810,7 +2831,7 @@ static void ov6xx0_configure(struct sd *sd)
pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n");
break;
default:
- pr_err("FATAL: Unknown sensor version: 0x%02x\n", rc);
+ PERR("FATAL: Unknown sensor version: 0x%02x\n", rc);
return;
}
@@ -2907,6 +2928,7 @@ static void ov51x_upload_quan_tables(struct sd *sd)
7, 7, 7, 7, 7, 7, 8, 8
};
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
const unsigned char *pYTable, *pUVTable;
unsigned char val0, val1;
int i, size, reg = R51x_COMP_LUT_BEGIN;
@@ -3300,7 +3322,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
} else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
ov_hires_configure(sd);
} else {
- pr_err("Can't determine sensor slave IDs\n");
+ PERR("Can't determine sensor slave IDs\n");
goto error;
}
@@ -3433,7 +3455,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
}
return gspca_dev->usb_err;
error:
- PDEBUG(D_ERR, "OV519 Config failed");
+ PERR("OV519 Config failed");
return -EINVAL;
}
@@ -3459,6 +3481,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
*/
static void ov511_mode_init_regs(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int hsegs, vsegs, packet_size, fps, needed;
int interlaced = 0;
struct usb_host_interface *alt;
@@ -3467,7 +3490,7 @@ static void ov511_mode_init_regs(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
- pr_err("Couldn't get altsetting\n");
+ PERR("Couldn't get altsetting\n");
sd->gspca_dev.usb_err = -EIO;
return;
}
@@ -3583,6 +3606,7 @@ static void ov511_mode_init_regs(struct sd *sd)
*/
static void ov518_mode_init_regs(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int hsegs, vsegs, packet_size;
struct usb_host_interface *alt;
struct usb_interface *intf;
@@ -3590,7 +3614,7 @@ static void ov518_mode_init_regs(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
- pr_err("Couldn't get altsetting\n");
+ PERR("Couldn't get altsetting\n");
sd->gspca_dev.usb_err = -EIO;
return;
}
@@ -3750,6 +3774,8 @@ static void ov519_mode_init_regs(struct sd *sd)
/* windows reads 0x55 at this point, why? */
};
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
/******** Set the mode ********/
switch (sd->sensor) {
default:
@@ -3865,11 +3891,10 @@ static void ov519_mode_init_regs(struct sd *sd)
static void mode_init_ov_sensor_regs(struct sd *sd)
{
- struct gspca_dev *gspca_dev;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int qvga, xstart, xend, ystart, yend;
u8 v;
- gspca_dev = &sd->gspca_dev;
qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
/******** Mode (VGA/QVGA) and sensor specific regs ********/
@@ -4304,7 +4329,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
/* Frame end */
if ((in[9] + 1) * 8 != gspca_dev->width ||
(in[10] + 1) * 8 != gspca_dev->height) {
- PDEBUG(D_ERR, "Invalid frame size, got: %dx%d,"
+ PERR("Invalid frame size, got: %dx%d,"
" requested: %dx%d\n",
(in[9] + 1) * 8, (in[10] + 1) * 8,
gspca_dev->width, gspca_dev->height);
@@ -4355,7 +4380,7 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
except that they may contain part of the footer), are
numbered 0 */
else if (sd->packet_nr == 0 || data[len]) {
- PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)",
+ PERR("Invalid packet nr: %d (expect: %d)",
(int)data[len], (int)sd->packet_nr);
gspca_dev->last_packet_type = DISCARD_PACKET;
return;
@@ -4898,7 +4923,7 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
if (hdl->error) {
- pr_err("Could not initialize controls\n");
+ PERR("Could not initialize controls\n");
return hdl->error;
}
if (gspca_dev->autogain)
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index bb09d7884b8..2e28c81a03a 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -690,7 +690,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
case 0x03:
break;
default:
- PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
+ PERR("sccb status 0x%02x, attempt %d/5",
data, i + 1);
}
}
diff --git a/drivers/media/usb/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c
index 3b75097dd34..83519be94e5 100644
--- a/drivers/media/usb/gspca/pac207.c
+++ b/drivers/media/usb/gspca/pac207.c
@@ -373,7 +373,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
unsigned char *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n;
diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c
index add6f725ba5..6008c8d546a 100644
--- a/drivers/media/usb/gspca/pac7302.c
+++ b/drivers/media/usb/gspca/pac7302.c
@@ -344,13 +344,10 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
reg_w_page(gspca_dev, page3, page3_len);
break;
default:
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- PDEBUG(D_ERR|D_STREAM,
- "Incorrect variable sequence");
+ PERR("Incorrect variable sequence");
return;
}
-#endif
while (len > 0) {
if (len < 8) {
reg_w_buf(gspca_dev,
@@ -795,7 +792,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *image;
u8 *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
@@ -843,7 +840,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
u8 index;
u8 value;
diff --git a/drivers/media/usb/gspca/pac7311.c b/drivers/media/usb/gspca/pac7311.c
index a12dfbf6e05..1a5bdc853a8 100644
--- a/drivers/media/usb/gspca/pac7311.c
+++ b/drivers/media/usb/gspca/pac7311.c
@@ -262,8 +262,7 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
break;
default:
if (len > USB_BUF_SZ) {
- PDEBUG(D_ERR|D_STREAM,
- "Incorrect variable sequence");
+ PERR("Incorrect variable sequence");
return;
}
while (len > 0) {
@@ -575,7 +574,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *image;
unsigned char *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
diff --git a/drivers/media/usb/gspca/pac_common.h b/drivers/media/usb/gspca/pac_common.h
index 8462a7c1a33..fbc5e226c3e 100644
--- a/drivers/media/usb/gspca/pac_common.h
+++ b/drivers/media/usb/gspca/pac_common.h
@@ -71,7 +71,7 @@ static const unsigned char pac_sof_marker[5] =
+----------+
*/
-static unsigned char *pac_find_sof(u8 *sof_read,
+static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev, u8 *sof_read,
unsigned char *m, int len)
{
int i;
diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
index 03fa3fd940b..39b6b2e0296 100644
--- a/drivers/media/usb/gspca/sn9c2028.c
+++ b/drivers/media/usb/gspca/sn9c2028.c
@@ -650,13 +650,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
result = sn9c2028_read1(gspca_dev);
if (result < 0)
- PDEBUG(D_ERR, "Camera Stop read failed");
+ PERR("Camera Stop read failed");
memset(data, 0, 6);
data[0] = 0x14;
result = sn9c2028_command(gspca_dev, data);
if (result < 0)
- PDEBUG(D_ERR, "Camera Stop command failed");
+ PERR("Camera Stop command failed");
}
/* Include sn9c2028 sof detection functions */
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index 4ec544f4a84..ead9a1f5851 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -1598,7 +1598,7 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
}
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c
index 104ae25275b..3fe207e038c 100644
--- a/drivers/media/usb/gspca/sonixb.c
+++ b/drivers/media/usb/gspca/sonixb.c
@@ -1379,27 +1379,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
}
-static int sd_querymenu(struct gspca_dev *gspca_dev,
- struct v4l2_querymenu *menu)
-{
- switch (menu->id) {
- case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
- strcpy((char *) menu->name, "NoFliker");
- return 0;
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
- }
- return -EINVAL;
-}
-
#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
@@ -1428,7 +1407,6 @@ static const struct sd_desc sd_desc = {
.start = sd_start,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
- .querymenu = sd_querymenu,
.dq_callback = do_autogain,
#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c
index 671d0c6dece..3b5ccb1c4cd 100644
--- a/drivers/media/usb/gspca/sonixj.c
+++ b/drivers/media/usb/gspca/sonixj.c
@@ -31,32 +31,26 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
MODULE_LICENSE("GPL");
-/* controls */
-enum e_ctrl {
- BRIGHTNESS,
- CONTRAST,
- COLORS,
- BLUE,
- RED,
- GAMMA,
- EXPOSURE,
- AUTOGAIN,
- GAIN,
- HFLIP,
- VFLIP,
- SHARPNESS,
- ILLUM,
- FREQ,
- NCTRLS /* number of controls */
-};
-
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- struct gspca_ctrl ctrls[NCTRLS];
-
atomic_t avg_lum;
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *saturation;
+ struct { /* red/blue balance control cluster */
+ struct v4l2_ctrl *red_bal;
+ struct v4l2_ctrl *blue_bal;
+ };
+ struct { /* hflip/vflip control cluster */
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+ };
+ struct v4l2_ctrl *gamma;
+ struct v4l2_ctrl *illum;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *freq;
u32 exposure;
struct work_struct work;
@@ -127,283 +121,6 @@ static void qual_upd(struct work_struct *work);
#define SEN_CLK_EN 0x20 /* enable sensor clock */
#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */
-/* V4L2 controls supported by the driver */
-static void setbrightness(struct gspca_dev *gspca_dev);
-static void setcontrast(struct gspca_dev *gspca_dev);
-static void setcolors(struct gspca_dev *gspca_dev);
-static void setredblue(struct gspca_dev *gspca_dev);
-static void setgamma(struct gspca_dev *gspca_dev);
-static void setexposure(struct gspca_dev *gspca_dev);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static void setgain(struct gspca_dev *gspca_dev);
-static void sethvflip(struct gspca_dev *gspca_dev);
-static void setsharpness(struct gspca_dev *gspca_dev);
-static void setillum(struct gspca_dev *gspca_dev);
-static void setfreq(struct gspca_dev *gspca_dev);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x80,
- },
- .set_control = setbrightness
- },
-[CONTRAST] = {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
-#define CONTRAST_MAX 127
- .maximum = CONTRAST_MAX,
- .step = 1,
- .default_value = 20,
- },
- .set_control = setcontrast
- },
-[COLORS] = {
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 40,
- .step = 1,
-#define COLORS_DEF 25
- .default_value = COLORS_DEF,
- },
- .set_control = setcolors
- },
-[BLUE] = {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = 24,
- .maximum = 40,
- .step = 1,
- .default_value = 32,
- },
- .set_control = setredblue
- },
-[RED] = {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = 24,
- .maximum = 40,
- .step = 1,
- .default_value = 32,
- },
- .set_control = setredblue
- },
-[GAMMA] = {
- {
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = 0,
- .maximum = 40,
- .step = 1,
-#define GAMMA_DEF 20
- .default_value = GAMMA_DEF,
- },
- .set_control = setgamma
- },
-[EXPOSURE] = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 500,
- .maximum = 1500,
- .step = 1,
- .default_value = 1024
- },
- .set_control = setexposure
- },
-[AUTOGAIN] = {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = sd_setautogain,
- },
-[GAIN] = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 4,
- .maximum = 49,
- .step = 1,
- .default_value = 15
- },
- .set_control = setgain
- },
-[HFLIP] = {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = sethvflip
- },
-[VFLIP] = {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vflip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = sethvflip
- },
-[SHARPNESS] = {
- {
- .id = V4L2_CID_SHARPNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Sharpness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 90,
- },
- .set_control = setsharpness
- },
-[ILLUM] = {
- {
- .id = V4L2_CID_ILLUMINATORS_1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Illuminator / infrared",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = setillum
- },
-/* ov7630/ov7648/ov7660 only */
-[FREQ] = {
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Light frequency filter",
- .minimum = 0,
- .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
- .step = 1,
- .default_value = 1,
- },
- .set_control = setfreq
- },
-};
-
-/* table of the disabled controls */
-static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_GC0307] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_HV7131R] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << FREQ),
-
-[SENSOR_MI0360] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_MI0360B] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_MO4000] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_MT9V111] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_OM6802] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_OV7630] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP),
-
-[SENSOR_OV7648] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP),
-
-[SENSOR_OV7660] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP),
-
-[SENSOR_PO1030] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_PO2030N] = (1 << FREQ),
-
-[SENSOR_SOI768] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_SP80708] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-};
-
static const struct v4l2_pix_format cif_mode[] = {
{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 352,
@@ -1442,12 +1159,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_err < 0)
return;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_r: buffer overflow\n");
+ PERR("reg_r: buffer overflow\n");
return;
}
-#endif
+
ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
0,
@@ -1496,12 +1212,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
return;
PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..",
value, buffer[0], buffer[1]);
-#ifdef GSPCA_DEBUG
+
if (len > USB_BUF_SZ) {
- pr_err("reg_w: buffer overflow\n");
+ PERR("reg_w: buffer overflow\n");
return;
}
-#endif
+
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -1822,7 +1538,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(vga_mode);
}
cam->npkt = 24; /* 24 packets per ISOC message */
- cam->ctrls = sd->ctrls;
sd->ag_cnt = -1;
sd->quality = QUALITY_DEF;
@@ -1888,9 +1603,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
break;
}
- if (sd->sensor == SENSOR_OM6802)
- sd->ctrls[SHARPNESS].def = 0x10;
-
/* Note we do not disable the sensor clock here (power saving mode),
as that also disables the button on the cam. */
reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1899,13 +1611,92 @@ static int sd_init(struct gspca_dev *gspca_dev)
sn9c1xx = sn_tb[sd->sensor];
sd->i2c_addr = sn9c1xx[9];
- gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
- if (!(sd->flags & F_ILLUM))
- gspca_dev->ctrl_dis |= (1 << ILLUM);
-
return gspca_dev->usb_err;
}
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 14);
+
+ sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+#define CONTRAST_MAX 127
+ sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, CONTRAST_MAX, 1, 20);
+#define COLORS_DEF 25
+ sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 40, 1, COLORS_DEF);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 24, 40, 1, 32);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 24, 40, 1, 32);
+#define GAMMA_DEF 20
+ sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 40, 1, GAMMA_DEF);
+
+ if (sd->sensor == SENSOR_OM6802)
+ sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 255, 1, 16);
+ else
+ sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 255, 1, 90);
+
+ if (sd->flags & F_ILLUM)
+ sd->illum = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE, 500, 1500, 1, 1024);
+ gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 4, 49, 1, 15);
+ sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ }
+
+ if (sd->sensor != SENSOR_ADCM1700 && sd->sensor != SENSOR_OV7660 &&
+ sd->sensor != SENSOR_PO1030 && sd->sensor != SENSOR_SOI768 &&
+ sd->sensor != SENSOR_SP80708)
+ gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+
+ if (sd->sensor == SENSOR_HV7131R || sd->sensor == SENSOR_OV7630 ||
+ sd->sensor == SENSOR_OV7648 || sd->sensor == SENSOR_PO2030N)
+ sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ if (sd->sensor == SENSOR_OV7630 || sd->sensor == SENSOR_OV7648 ||
+ sd->sensor == SENSOR_OV7660)
+ sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->red_bal);
+ if (sd->sensor == SENSOR_PO2030N) {
+ v4l2_ctrl_cluster(2, &sd->vflip);
+ v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
+ }
+
+ return 0;
+}
+