summaryrefslogtreecommitdiff
path: root/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/Kconfig77
-rw-r--r--drivers/media/video/Makefile4
-rw-r--r--drivers/media/video/adv7343.c1
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c2
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c14
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c1
-rw-r--r--drivers/media/video/cafe_ccic.c1
-rw-r--r--drivers/media/video/cx18/cx18-cards.c8
-rw-r--r--drivers/media/video/cx18/cx18-cards.h18
-rw-r--r--drivers/media/video/cx18/cx18-driver.c41
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c2
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c58
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-conf-reg.h8
-rw-r--r--drivers/media/video/cx231xx/cx231xx-i2c.c1
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c4
-rw-r--r--drivers/media/video/cx23885/cimax2.c1
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c57
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c77
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c30
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c54
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c1
-rw-r--r--drivers/media/video/cx23885/cx23885.h14
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c15
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c13
-rw-r--r--drivers/media/video/cx88/cx88-cards.c56
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c16
-rw-r--r--drivers/media/video/cx88/cx88-input.c26
-rw-r--r--drivers/media/video/cx88/cx88.h1
-rw-r--r--drivers/media/video/davinci/Makefile15
-rw-r--r--drivers/media/video/davinci/ccdc_hw_device.h110
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c978
-rw-r--r--drivers/media/video/davinci/dm355_ccdc_regs.h310
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c878
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc_regs.h145
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c2124
-rw-r--r--drivers/media/video/davinci/vpif.c234
-rw-r--r--drivers/media/video/davinci/vpif.h632
-rw-r--r--drivers/media/video/davinci/vpif_display.c1679
-rw-r--r--drivers/media/video/davinci/vpif_display.h175
-rw-r--r--drivers/media/video/davinci/vpss.c301
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c28
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c161
-rw-r--r--drivers/media/video/em28xx/em28xx.h1
-rw-r--r--drivers/media/video/gspca/Kconfig21
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/conex.c2
-rw-r--r--drivers/media/video/gspca/etoms.c4
-rw-r--r--drivers/media/video/gspca/gspca.c66
-rw-r--r--drivers/media/video/gspca/gspca.h5
-rw-r--r--drivers/media/video/gspca/jeilinj.c388
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c4
-rw-r--r--drivers/media/video/gspca/pac7311.c1
-rw-r--r--drivers/media/video/gspca/sn9c20x.c38
-rw-r--r--drivers/media/video/gspca/sonixj.c21
-rw-r--r--drivers/media/video/gspca/spca501.c2
-rw-r--r--drivers/media/video/gspca/spca506.c2
-rw-r--r--drivers/media/video/gspca/spca508.c59
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c4
-rw-r--r--drivers/media/video/gspca/sunplus.c14
-rw-r--r--drivers/media/video/gspca/t613.c210
-rw-r--r--drivers/media/video/gspca/tv8532.c2
-rw-r--r--drivers/media/video/gspca/vc032x.c873
-rw-r--r--drivers/media/video/gspca/zc3xx.c2
-rw-r--r--drivers/media/video/hdpvr/hdpvr-control.c24
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c12
-rw-r--r--drivers/media/video/hdpvr/hdpvr-i2c.c1
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c6
-rw-r--r--drivers/media/video/ir-kbd-i2c.c44
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c70
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h3
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c3
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c13
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c2
-rw-r--r--drivers/media/video/meye.c3
-rw-r--r--drivers/media/video/mt9m001.c435
-rw-r--r--drivers/media/video/mt9m111.c524
-rw-r--r--drivers/media/video/mt9t031.c491
-rw-r--r--drivers/media/video/mt9v022.c434
-rw-r--r--drivers/media/video/mx1_camera.c78
-rw-r--r--drivers/media/video/mx3_camera.c207
-rw-r--r--drivers/media/video/ov772x.c381
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c1
-rw-r--r--drivers/media/video/pwc/pwc-if.c78
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c2
-rw-r--r--drivers/media/video/pwc/pwc.h7
-rw-r--r--drivers/media/video/pxa_camera.c358
-rw-r--r--drivers/media/video/saa6588.c60
-rw-r--r--drivers/media/video/saa7134/Kconfig1
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c242
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c213
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c17
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c12
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c5
-rw-r--r--drivers/media/video/saa7134/saa7134.h5
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c1058
-rw-r--r--drivers/media/video/soc_camera.c725
-rw-r--r--drivers/media/video/soc_camera_platform.c163
-rw-r--r--drivers/media/video/stk-webcam.c1
-rw-r--r--drivers/media/video/stv680.c9
-rw-r--r--drivers/media/video/tuner-core.c4
-rw-r--r--drivers/media/video/tveeprom.c4
-rw-r--r--drivers/media/video/tvp514x.c1030
-rw-r--r--drivers/media/video/tvp514x_regs.h10
-rw-r--r--drivers/media/video/tw9910.c361
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c255
-rw-r--r--drivers/media/video/uvc/uvc_driver.c570
-rw-r--r--drivers/media/video/uvc/uvc_isight.c7
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c277
-rw-r--r--drivers/media/video/uvc/uvc_video.c434
-rw-r--r--drivers/media/video/uvc/uvcvideo.h278
-rw-r--r--drivers/media/video/v4l1-compat.c5
-rw-r--r--drivers/media/video/v4l2-common.c52
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c67
-rw-r--r--drivers/media/video/v4l2-ioctl.c33
-rw-r--r--drivers/media/video/vino.c1
-rw-r--r--drivers/media/video/w9968cf.c1
-rw-r--r--drivers/media/video/zoran/zoran_card.c3
-rw-r--r--drivers/media/video/zr364xx.c1226
126 files changed, 15819 insertions, 4597 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index dcf9fa9264bb..14a1b616087f 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -203,9 +203,9 @@ config VIDEO_CS53L32A
module will be called cs53l32a.
config VIDEO_M52790
- tristate "Mitsubishi M52790 A/V switch"
- depends on VIDEO_V4L2 && I2C
- ---help---
+ tristate "Mitsubishi M52790 A/V switch"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
Support for the Mitsubishi M52790 A/V switch.
To compile this driver as a module, choose M here: the
@@ -493,6 +493,28 @@ config VIDEO_UPD64083
endmenu # encoder / decoder chips
+config DISPLAY_DAVINCI_DM646X_EVM
+ tristate "DM646x EVM Video Display"
+ depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ select VIDEO_ADV7343
+ select VIDEO_THS7303
+ help
+ Support for DaVinci based display device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called davincihd_display.
+
+config VIDEO_DAVINCI_VPIF
+ tristate "DaVinci VPIF Driver"
+ depends on DISPLAY_DAVINCI_DM646X_EVM
+ help
+ Support for DaVinci VPIF Driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif.
+
config VIDEO_VIVI
tristate "Virtual Video Driver"
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
@@ -505,6 +527,55 @@ config VIDEO_VIVI
Say Y here if you want to test video apps or debug V4L devices.
In doubt, say N.
+config VIDEO_VPSS_SYSTEM
+ tristate "VPSS System module driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for vpss system module for video driver
+ default y
+
+config VIDEO_VPFE_CAPTURE
+ tristate "VPFE Video Capture Driver"
+ depends on VIDEO_V4L2 && ARCH_DAVINCI
+ select VIDEOBUF_DMA_CONTIG
+ help
+ Support for DMXXXX VPFE based frame grabber. This is the
+ common V4L2 module for following DMXXX SoCs from Texas
+ Instruments:- DM6446 & DM355.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+ tristate "DM6446 CCDC HW module"
+ depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from slave decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+ tristate "DM355 CCDC HW module"
+ depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from a slave decoders
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
source "drivers/media/video/bt8xx/Kconfig"
config VIDEO_PMS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9f2e3214a482..00fb23e64374 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -154,12 +154,16 @@ obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+obj-$(CONFIG_ARCH_DAVINCI) += davinci/
+
obj-$(CONFIG_VIDEO_AU0828) += au0828/
obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
+obj-$(CONFIG_ARCH_DAVINCI) += davinci/
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
index 30f5caf5dda5..df26f2fe44eb 100644
--- a/drivers/media/video/adv7343.c
+++ b/drivers/media/video/adv7343.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/videodev2.h>
#include <linux/uaccess.h>
-#include <linux/version.h>
#include <media/adv7343.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 14baffc22192..b8a4b52e8d47 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -151,7 +151,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
dprintk(2, "%s()\n", __func__);
if (dev->urb_streaming) {
- dprintk(2, "%s: iso xfer already running!\n", __func__);
+ dprintk(2, "%s: bulk xfer already running!\n", __func__);
return 0;
}
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
index 13e494365e70..cbdb65c34f21 100644
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -320,7 +320,6 @@ static struct i2c_algorithm au0828_i2c_algo_template = {
static struct i2c_adapter au0828_i2c_adap_template = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
- .id = I2C_HW_B_AU0828,
.algo = &au0828_i2c_algo_template,
};
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index ca6558c394be..b42251fa96ba 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -1274,6 +1274,7 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.tuner_type = TUNER_TEMIC_PAL,
.tuner_addr = ADDR_UNSET,
+ .has_remote = 1,
},
/* ---- card 0x3c ---------------------------------- */
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 8cc6dd28d6a7..939d1e512974 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2652,6 +2652,8 @@ static int bttv_querycap(struct file *file, void *priv,
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
+ if (btv->has_saa6588)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
@@ -4593,14 +4595,10 @@ static int bttv_resume(struct pci_dev *pci_dev)
#endif
static struct pci_device_id bttv_pci_tbl[] = {
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
{0,}
};
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index ebd1ee9dc871..beda363418b0 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -352,7 +352,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
/* bt878 */
strlcpy(btv->c.i2c_adap.name, "bt878",
sizeof(btv->c.i2c_adap.name));
- btv->c.i2c_adap.id = I2C_HW_B_BT848; /* FIXME */
btv->c.i2c_adap.algo = &bttv_algo;
} else {
/* bt848 */
@@ -362,7 +361,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
strlcpy(btv->c.i2c_adap.name, "bttv",
sizeof(btv->c.i2c_adap.name));
- btv->c.i2c_adap.id = I2C_HW_B_BT848;
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
sizeof(bttv_i2c_algo_bit_template));
btv->i2c_algo.udelay = i2c_udelay;
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 2f289d981fe6..3e7b48e73b01 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -308,6 +308,7 @@ int bttv_input_init(struct bttv *btv)
ir->mask_keyup = 0x008000;
ir->polling = 50; // ms
break;
+ case BTTV_BOARD_ASKEY_CPH03X:
case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
case BTTV_BOARD_CONTVFMI:
ir_codes = ir_codes_pixelview;
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index c4d181dde1ca..9c149a781294 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -490,7 +490,6 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
int ret;
cafe_smbus_enable_irq(cam);
- adap->id = I2C_HW_SMBUS_CAFE;
adap->owner = THIS_MODULE;
adap->algo = &cafe_smbus_algo;
strcpy(adap->name, "cafe_ccic");
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 36f2d76006fd..f11e47a58286 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -56,7 +56,8 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
.hw_audio_ctrl = CX18_HW_418_AV,
.hw_muxer = CX18_HW_CS5345,
.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
- CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+ CX18_HW_Z8F0811_IR_HAUP,
.video_inputs = {
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
{ CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
@@ -102,7 +103,8 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
.hw_audio_ctrl = CX18_HW_418_AV,
.hw_muxer = CX18_HW_CS5345,
.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
- CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+ CX18_HW_Z8F0811_IR_HAUP,
.video_inputs = {
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
{ CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
@@ -204,7 +206,7 @@ static const struct cx18_card cx18_card_mpc718 = {
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_418_AV,
.hw_muxer = CX18_HW_GPIO_MUX,
- .hw_all = CX18_HW_418_AV | CX18_HW_TUNER |
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
.video_inputs = {
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index 3c552b6b7c4d..444e3c7c563e 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -22,13 +22,17 @@
*/
/* hardware flags */
-#define CX18_HW_TUNER (1 << 0)
-#define CX18_HW_TVEEPROM (1 << 1)
-#define CX18_HW_CS5345 (1 << 2)
-#define CX18_HW_DVB (1 << 3)
-#define CX18_HW_418_AV (1 << 4)
-#define CX18_HW_GPIO_MUX (1 << 5)
-#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
+#define CX18_HW_TUNER (1 << 0)
+#define CX18_HW_TVEEPROM (1 << 1)
+#define CX18_HW_CS5345 (1 << 2)
+#define CX18_HW_DVB (1 << 3)
+#define CX18_HW_418_AV (1 << 4)
+#define CX18_HW_GPIO_MUX (1 << 5)
+#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
+#define CX18_HW_Z8F0811_IR_TX_HAUP (1 << 7)
+#define CX18_HW_Z8F0811_IR_RX_HAUP (1 << 8)
+#define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \
+ CX18_HW_Z8F0811_IR_TX_HAUP)
/* video inputs */
#define CX18_CARD_INPUT_VID_TUNER 1
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 92026e82e10e..dd0224f328ad 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -268,6 +268,20 @@ static void cx18_iounmap(struct cx18 *cx)
}
}
+static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len)
+{
+ int i;
+
+ CX18_INFO("eeprom dump:\n");
+ for (i = 0; i < len; i++) {
+ if (0 == (i % 16))
+ CX18_INFO("eeprom %02x:", i);
+ printk(KERN_CONT " %02x", eedata[i]);
+ if (15 == (i % 16))
+ printk(KERN_CONT "\n");
+ }
+}
+
/* Hauppauge card? get values from tveeprom */
void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
{
@@ -279,8 +293,26 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
c.adapter = &cx->i2c_adap[0];
c.addr = 0xA0 >> 1;
- tveeprom_read(&c, eedata, sizeof(eedata));
- tveeprom_hauppauge_analog(&c, tv, eedata);
+ memset(tv, 0, sizeof(*tv));
+ if (tveeprom_read(&c, eedata, sizeof(eedata)))
+ return;
+
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ tveeprom_hauppauge_analog(&c, tv, eedata);
+ break;
+ case CX18_CARD_YUAN_MPC718:
+ tv->model = 0x718;
+ cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+ CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
+ eedata[2], eedata[1], eedata[4], eedata[3]);
+ break;
+ default:
+ tv->model = 0xffffffff;
+ cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+ break;
+ }
}
static void cx18_process_eeprom(struct cx18 *cx)
@@ -298,6 +330,11 @@ static void cx18_process_eeprom(struct cx18 *cx)
case 74000 ... 74999:
cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
break;
+ case 0x718:
+ return;
+ case 0xffffffff:
+ CX18_INFO("Unknown EEPROM encoding\n");
+ return;
case 0:
CX18_ERR("Invalid EEPROM\n");
return;
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 29969c18949c..04d9c2508b86 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -690,7 +690,7 @@ int cx18_v4l2_open(struct file *filp)
int res;
struct video_device *video_dev = video_devdata(filp);
struct cx18_stream *s = video_get_drvdata(video_dev);
- struct cx18 *cx = s->cx;;
+ struct cx18 *cx = s->cx;
mutex_lock(&cx->serialize_lock);
if (cx18_init_on_first_open(cx)) {
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 8591e4fc359f..ba754e8056fb 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -28,6 +28,7 @@
#include "cx18-gpio.h"
#include "cx18-i2c.h"
#include "cx18-irq.h"
+#include <media/ir-kbd-i2c.h>
#define CX18_REG_I2C_1_WR 0xf15000
#define CX18_REG_I2C_1_RD 0xf15008
@@ -40,16 +41,20 @@
#define GETSDL_BIT 0x0008
#define CX18_CS5345_I2C_ADDR 0x4c
+#define CX18_Z8F0811_IR_TX_I2C_ADDR 0x70
+#define CX18_Z8F0811_IR_RX_I2C_ADDR 0x71
/* This array should match the CX18_HW_ defines */
static const u8 hw_addrs[] = {
- 0, /* CX18_HW_TUNER */
- 0, /* CX18_HW_TVEEPROM */
- CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */
- 0, /* CX18_HW_DVB */
- 0, /* CX18_HW_418_AV */
- 0, /* CX18_HW_GPIO_MUX */
- 0, /* CX18_HW_GPIO_RESET_CTRL */
+ 0, /* CX18_HW_TUNER */
+ 0, /* CX18_HW_TVEEPROM */
+ CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */
+ 0, /* CX18_HW_DVB */
+ 0, /* CX18_HW_418_AV */
+ 0, /* CX18_HW_GPIO_MUX */
+ 0, /* CX18_HW_GPIO_RESET_CTRL */
+ CX18_Z8F0811_IR_TX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_TX_HAUP */
+ CX18_Z8F0811_IR_RX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_RX_HAUP */
};
/* This array should match the CX18_HW_ defines */
@@ -62,6 +67,8 @@ static const u8 hw_bus[] = {
0, /* CX18_HW_418_AV */
0, /* CX18_HW_GPIO_MUX */
0, /* CX18_HW_GPIO_RESET_CTRL */
+ 0, /* CX18_HW_Z8F0811_IR_TX_HAUP */
+ 0, /* CX18_HW_Z8F0811_IR_RX_HAUP */
};
/* This array should match the CX18_HW_ defines */
@@ -73,6 +80,8 @@ static const char * const hw_modules[] = {
NULL, /* CX18_HW_418_AV */
NULL, /* CX18_HW_GPIO_MUX */
NULL, /* CX18_HW_GPIO_RESET_CTRL */
+ NULL, /* CX18_HW_Z8F0811_IR_TX_HAUP */
+ NULL, /* CX18_HW_Z8F0811_IR_RX_HAUP */
};
/* This array should match the CX18_HW_ defines */
@@ -84,8 +93,37 @@ static const char * const hw_devicenames[] = {
"cx23418_AV",
"gpio_mux",
"gpio_reset_ctrl",
+ "ir_tx_z8f0811_haup",
+ "ir_rx_z8f0811_haup",
};
+static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
+ u8 addr)
+{
+ struct i2c_board_info info;
+ struct IR_i2c_init_data ir_init_data;
+ unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, type, I2C_NAME_SIZE);
+
+ /* Our default information for ir-kbd-i2c.c to use */
+ switch (hw) {
+ case CX18_HW_Z8F0811_IR_RX_HAUP:
+ memset(&ir_init_data, 0, sizeof(struct IR_i2c_init_data));
+ ir_init_data.ir_codes = ir_codes_hauppauge_new;
+ ir_init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ ir_init_data.type = IR_TYPE_RC5;
+ ir_init_data.name = "CX23418 Z8F0811 Hauppauge";
+ info.platform_data = &ir_init_data;
+ break;
+ default:
+ break;
+ }
+
+ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+}
+
int cx18_i2c_register(struct cx18 *cx, unsigned idx)
{
struct v4l2_subdev *sd;
@@ -115,11 +153,14 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return sd != NULL ? 0 : -1;
}
+ if (hw & CX18_HW_Z8F0811_IR_HAUP)
+ return cx18_i2c_new_ir(adap, hw, type, hw_addrs[idx]);
+
/* Is it not an I2C device or one we do not wish to register? */
if (!hw_addrs[idx])
return -1;
- /* It's an I2C device other than an analog tuner */
+ /* It's an I2C device other than an analog tuner or IR chip */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]);
if (sd != NULL)
sd->grp_id = hw;
@@ -190,7 +231,6 @@ static int cx18_getsda(void *data)
/* template for i2c-bit-algo */
static struct i2c_adapter cx18_i2c_adap_template = {
.name = "cx18 i2c driver",
- .id = I2C_HW_B_CX2341X,
.algo = NULL, /* set by i2c-algo-bit */
.algo_data = NULL, /* filled from template */
.owner = THIS_MODULE,
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index d7b1921e6666..fc76e4d6ffa7 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -605,7 +605,7 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp)
if (ret)
return ret;
- if (inp < 0 || inp >= cx->nof_inputs)
+ if (inp >= cx->nof_inputs)
return -EINVAL;
if (inp == cx->active_input) {
diff --git a/drivers/media/video/cx231xx/cx231xx-conf-reg.h b/drivers/media/video/cx231xx/cx231xx-conf-reg.h
index a6f398a175c5..31a8759f6e54 100644
--- a/drivers/media/video/cx231xx/cx231xx-conf-reg.h
+++ b/drivers/media/video/cx231xx/cx231xx-conf-reg.h
@@ -60,10 +60,10 @@
#define PWR_RESETOUT_EN 0x100 /* bit8 */
enum AV_MODE{
- POLARIS_AVMODE_DEFAULT = 0,
- POLARIS_AVMODE_DIGITAL = 0x10,
- POLARIS_AVMODE_ANALOGT_TV = 0x20,
- POLARIS_AVMODE_ENXTERNAL_AV = 0x30,
+ POLARIS_AVMODE_DEFAULT = 0,
+ POLARIS_AVMODE_DIGITAL = 0x10,
+ POLARIS_AVMODE_ANALOGT_TV = 0x20,
+ POLARIS_AVMODE_ENXTERNAL_AV = 0x30,
};
diff --git a/drivers/media/video/cx231xx/cx231xx-i2c.c b/drivers/media/video/cx231xx/cx231xx-i2c.c
index 33219dc4d649..58d9cc0867b9 100644
--- a/drivers/media/video/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/video/cx231xx/cx231xx-i2c.c
@@ -432,7 +432,6 @@ static struct i2c_algorithm cx231xx_algo = {
static struct i2c_adapter cx231xx_adap_template = {
.owner = THIS_MODULE,
.name = "cx231xx",
- .id = I2C_HW_B_CX231XX,
.algo = &cx231xx_algo,
};
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 609bae6098d3..36503725d973 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -923,8 +923,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = dev->format->fourcc;;
- f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;;
+ f->fmt.pix.pixelformat = dev->format->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
index 08582e58bdbf..0316257b7345 100644
--- a/drivers/media/video/cx23885/cimax2.c
+++ b/drivers/media/video/cx23885/cimax2.c
@@ -443,6 +443,7 @@ int netup_ci_init(struct cx23885_tsport *port)
goto err;
INIT_WORK(&state->work, netup_read_ci_status);
+ schedule_work(&state->work);
ci_dbg_print("%s: CI initialized!\n", __func__);
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 1a1048b18f70..6c3b51ce3372 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -630,6 +630,39 @@ int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
return retval;
}
+void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+ u32 val;
+
+ /* Set the gpio value */
+ mc417_register_read(dev, 0x900C, &val);
+ val |= (mask & 0x000ffff);
+ mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+ u32 val;
+
+ /* Clear the gpio value */
+ mc417_register_read(dev, 0x900C, &val);
+ val &= ~(mask & 0x0000ffff);
+ mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+ u32 val;
+
+ /* Enable GPIO direction bits */
+ mc417_register_read(dev, 0x9020, &val);
+ if (asoutput)
+ val |= (mask & 0x0000ffff);
+ else
+ val &= ~(mask & 0x0000ffff);
+
+ mc417_register_write(dev, 0x9020, val);
+}
/* ------------------------------------------------------------------ */
/* MPEG encoder API */
@@ -955,25 +988,8 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
IVTV_CMD_HW_BLOCKS_RST);
- /* Restore GPIO settings, make sure EIO14 is enabled as an output. */
- dprintk(2, "%s: GPIO output EIO 0-15 was = 0x%x\n",
- __func__, gpio_output);
- /* Power-up seems to have GPIOs AFU. This was causing digital side
- * to fail at power-up. Seems GPIOs should be set to 0x10ff0411 at
- * power-up.
- * gpio_output |= (1<<14);
- */
- /* Note: GPIO14 is specific to the HVR1800 here */
- gpio_output = 0x10ff0411 | (1<<14);
- retval |= mc417_register_write(dev, 0x9020, gpio_output | (1<<14));
- dprintk(2, "%s: GPIO output EIO 0-15 now = 0x%x\n",
- __func__, gpio_output);
-
- dprintk(1, "%s: GPIO value EIO 0-15 was = 0x%x\n",
- __func__, value);
- value |= (1<<14);
- dprintk(1, "%s: GPIO value EIO 0-15 now = 0x%x\n",
- __func__, value);
+ /* F/W power up disturbs the GPIOs, restore state */
+ retval |= mc417_register_write(dev, 0x9020, gpio_output);
retval |= mc417_register_write(dev, 0x900C, value);
retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
@@ -1788,9 +1804,6 @@ int cx23885_417_register(struct cx23885_dev *dev)
return err;
}
- /* Initialize MC417 registers */
- cx23885_mc417_init(dev);
-
printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
dev->name, dev->v4l_device->num);
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index ce29b5e34a11..3143d85ef31d 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -201,6 +201,15 @@ struct cx23885_board cx23885_boards[] = {
.name = "Mygica X8506 DMB-TH",
.portb = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_MAGICPRO_PROHDTVE2] = {
+ .name = "Magic-Pro ProHDTV Extreme 2",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1850] = {
+ .name = "Hauppauge WinTV-HVR1850",
+ .portb = CX23885_MPEG_ENCODER,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -324,6 +333,14 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x14f1,
.subdevice = 0x8651,
.card = CX23885_BOARD_MYGICA_X8506,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8657,
+ .card = CX23885_BOARD_MAGICPRO_PROHDTVE2,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8541,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1850,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -483,8 +500,13 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
/* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
* DVB-T and MPEG2 HW Encoder */
break;
+ case 85021:
+ /* WinTV-HVR1850 (PCIe, OEM, RCA in, IR, FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ break;
default:
- printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n",
+ printk(KERN_WARNING "%s: warning: "
+ "unknown hauppauge model #%d\n",
dev->name, tv.model);
break;
}
@@ -574,13 +596,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
/* CX23417 GPIO's */
/* EIO15 Zilog Reset */
/* EIO14 S5H1409/CX24227 Reset */
+ mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+ /* Put the demod into reset and protect the eeprom */
+ mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+ mdelay(100);
+
+ /* Bring the demod and blaster out of reset */
+ mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+ mdelay(100);
/* Force the TDA8295A into reset and back */
- cx_set(GP0_IO, 0x00040004);
+ cx23885_gpio_enable(dev, GPIO_2, 1);
+ cx23885_gpio_set(dev, GPIO_2);
mdelay(20);
- cx_clear(GP0_IO, 0x00000004);
+ cx23885_gpio_clear(dev, GPIO_2);
mdelay(20);
- cx_set(GP0_IO, 0x00040004);
+ cx23885_gpio_set(dev, GPIO_2);
mdelay(20);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1200:
@@ -715,14 +747,45 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx23885_gpio_set(dev, GPIO_9);
break;
case CX23885_BOARD_MYGICA_X8506:
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
/* GPIO-1 reset XC5000 */
- /* GPIO-2 reset LGS8GL5 */
+ /* GPIO-2 reset LGS8GL5 / LGS8G75 */
cx_set(GP0_IO, 0x00060000);
cx_clear(GP0_IO, 0x00000006);
mdelay(100);
cx_set(GP0_IO, 0x00060006);
mdelay(100);
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ /* GPIO-0 656_CLK */
+ /* GPIO-1 656_D0 */
+ /* GPIO-2 Wake# */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ /* GPIO-19 IR_RX */
+ /* GPIO-20 C_IR_TX */
+ /* GPIO-21 I2S DAT */
+ /* GPIO-22 I2S WCLK */
+ /* GPIO-23 I2S BCLK */
+ /* ALT GPIO: EXP GPIO LATCH */
+
+ /* CX23417 GPIO's */
+ /* GPIO-14 S5H1411/CX24228 Reset */
+ /* GPIO-13 EEPROM write protect */
+ mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1);
+
+ /* Put the demod into reset and protect the eeprom */
+ mc417_gpio_clear(dev, GPIO_14 | GPIO_13);
+ mdelay(100);
+
+ /* Bring the demod out of reset */
+ mc417_gpio_set(dev, GPIO_14);
+ mdelay(100);
+
+ /* CX24228 GPIO */
+ /* Connected to IF / Mux */
+ break;
}
}
@@ -739,6 +802,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
/* FIXME: Implement me */
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
@@ -778,6 +842,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
@@ -827,6 +892,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
case CX23885_BOARD_MYGICA_X8506:
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
ts1->gen_ctrl_val = 0x5; /* Parallel */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -844,6 +910,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index bf7bb1c412fb..40d438d7234d 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -713,12 +713,26 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
dev->hwrevision = 0xa1;
break;
case 0x02:
- /* CX23885-13Z */
+ /* CX23885-13Z/14Z */
dev->hwrevision = 0xb0;
break;
case 0x03:
- /* CX23888-22Z */
- dev->hwrevision = 0xc0;
+ if (dev->pci->device == 0x8880) {
+ /* CX23888-21Z/22Z */
+ dev->hwrevision = 0xc0;
+ } else {
+ /* CX23885-14Z */
+ dev->hwrevision = 0xa4;
+ }
+ break;
+ case 0x04:
+ if (dev->pci->device == 0x8880) {
+ /* CX23888-31Z */
+ dev->hwrevision = 0xd0;
+ } else {
+ /* CX23885-15Z, CX23888-31Z */
+ dev->hwrevision = 0xa5;
+ }
break;
case 0x0e:
/* CX23887-15Z */
@@ -756,6 +770,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
/* Configure the internal memory */
if (dev->pci->device == 0x8880) {
+ /* Could be 887 or 888, assume a default */
dev->bridge = CX23885_BRIDGE_887;
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 25000000;
@@ -868,6 +883,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
__func__, dev->radio_type, dev->radio_addr);
+ /* The cx23417 encoder has GPIO's that need to be initialised
+ * before DVB, so that demodulators and tuners are out of
+ * reset before DVB uses them.
+ */
+ if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) ||
+ (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
+ cx23885_mc417_init(dev);
+
/* init hardware */
cx23885_reset(dev);
@@ -1250,6 +1273,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
switch (dev->bridge) {
case CX23885_BRIDGE_885:
case CX23885_BRIDGE_887:
+ case CX23885_BRIDGE_888:
/* enable irqs */
dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 86ac529e62be..022fad798fc2 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -396,7 +396,7 @@ static struct stv0900_reg stv0900_ts_regs[] = {
static struct stv0900_config netup_stv0900_config = {
.demod_address = 0x68,
- .xtal = 27000000,
+ .xtal = 8000000,
.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
.diseqc_mode = 2,/* 2/3 PWM */
.ts_config_regs = stv0900_ts_regs,
@@ -408,14 +408,14 @@ static struct stv0900_config netup_stv0900_config = {
static struct stv6110_config netup_stv6110_tunerconfig_a = {
.i2c_address = 0x60,
- .mclk = 27000000,
- .iq_wiring = 0,
+ .mclk = 16000000,
+ .clk_div = 1,
};
static struct stv6110_config netup_stv6110_tunerconfig_b = {
.i2c_address = 0x63,
- .mclk = 27000000,
- .iq_wiring = 1,
+ .mclk = 16000000,
+ .clk_div = 1,
};
static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -487,6 +487,26 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
port->set_frontend_save(fe, param) : -ENODEV;
}
+static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
+ .prod = LGS8GXX_PROD_LGS8G75,
+ .demod_address = 0x19,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 1,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 6500, /* 6.50 MHz */
+ .if_neg_center = 1,
+ .ext_adc = 0,
+ .adc_signed = 1,
+ .adc_vpp = 2, /* 1.6 Vpp */
+ .if_neg_edge = 1,
+};
+
+static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
+ .i2c_address = 0x61,
+ .if_khz = 6500,
+};
+
static int dvb_register(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
@@ -833,6 +853,30 @@ static int dvb_register(struct cx23885_tsport *port)
&mygica_x8506_xc5000_config);
}
break;
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &magicpro_prohdtve2_lgs8g75_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(xc5000_attach,
+ fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap,
+ &magicpro_prohdtve2_xc5000_config);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &hcw_s5h1411_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[0].i2c_adap,
+ &hauppauge_tda18271_config);
+ break;
+
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 384dec34134f..4172cb387420 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -283,7 +283,6 @@ static struct i2c_algorithm cx23885_i2c_algo_template = {
static struct i2c_adapter cx23885_i2c_adap_template = {
.name = "cx23885",
.owner = THIS_MODULE,
- .id = I2C_HW_B_CX23885,
.algo = &cx23885_i2c_algo_template,
};
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 214a55e943b7..86f26947bb78 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -76,6 +76,8 @@
#define CX23885_BOARD_HAUPPAUGE_HVR1255 20
#define CX23885_BOARD_HAUPPAUGE_HVR1210 21
#define CX23885_BOARD_MYGICA_X8506 22
+#define CX23885_BOARD_MAGICPRO_PROHDTVE2 23
+#define CX23885_BOARD_HAUPPAUGE_HVR1850 24
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -87,6 +89,12 @@
#define GPIO_7 0x00000080
#define GPIO_8 0x00000100
#define GPIO_9 0x00000200
+#define GPIO_10 0x00000400
+#define GPIO_11 0x00000800
+#define GPIO_12 0x00001000
+#define GPIO_13 0x00002000
+#define GPIO_14 0x00004000
+#define GPIO_15 0x00008000
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
@@ -331,6 +339,7 @@ struct cx23885_dev {
CX23885_BRIDGE_UNDEFINED = 0,
CX23885_BRIDGE_885 = 885,
CX23885_BRIDGE_887 = 887,
+ CX23885_BRIDGE_888 = 888,
} bridge;
/* Analog video */
@@ -395,7 +404,7 @@ struct sram_channel {
u32 cmds_start;
u32 ctrl_start;
u32 cdt;
- u32 fifo_start;;
+ u32 fifo_start;
u32 fifo_size;
u32 ptr1_reg;
u32 ptr2_reg;
@@ -504,6 +513,9 @@ extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
extern void cx23885_mc417_init(struct cx23885_dev *dev);
extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 0be51b65f098..1aeaf18a9bea 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -321,6 +321,15 @@ static void cx23885_initialize(struct i2c_client *client)
/* Select AFE clock pad output source */
cx25840_write(client, 0x144, 0x05);
+ /* Drive GPIO2 direction and values for HVR1700
+ * where an onboard mux selects the output of demodulator
+ * vs the 417. Failure to set this results in no DTV.
+ * It's safe to set this across all Hauppauge boards
+ * currently, regardless of the board type.
+ */
+ cx25840_write(client, 0x160, 0x1d);
+ cx25840_write(client, 0x164, 0x00);
+
/* Do the firmware load in a work handler to prevent.
Otherwise the kernel is blocked waiting for the
bit-banging i2c interface to finish uploading the
@@ -1578,12 +1587,6 @@ static int cx25840_probe(struct i2c_client *client,
state->id = id;
state->rev = device_id;
- if (state->is_cx23885) {
- /* Drive GPIO2 direction and values */
- cx25840_write(client, 0x160, 0x1d);
- cx25840_write(client, 0x164, 0x00);
- }
-
return 0;
}
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index 0df53b0d75d9..2a535d0403ed 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -98,9 +98,14 @@ int cx25840_loadfw(struct i2c_client *client)
const u8 *ptr;
int size, retval;
int MAX_BUF_SIZE = FWSEND;
+ u32 gpio_oe = 0, gpio_da = 0;
- if (state->is_cx23885)
+ if (state->is_cx23885) {
firmware = FWFILE_CX23885;
+ /* Preserve the GPIO OE and output bits */
+ gpio_oe = cx25840_read(client, 0x160);
+ gpio_da = cx25840_read(client, 0x164);
+ }
else if (state->is_cx231xx)
firmware = FWFILE_CX231XX;
@@ -142,5 +147,11 @@ int cx25840_loadfw(struct i2c_client *client)
size = fw->size;
release_firmware(fw);
+ if (state->is_cx23885) {
+ /* Restore GPIO configuration after f/w load */
+ cx25840_write(client, 0x160, gpio_oe);
+ cx25840_write(client, 0x164, gpio_da);
+ }
+
return check_fw_load(client, size);
}
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 39465301ec94..e5f07fbd5a35 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1283,6 +1283,51 @@ static const struct cx88_board cx88_boards[] = {
},
.mpeg = CX88_MPEG_DVB,
},
+ [CX88_BOARD_WINFAST_DTV2000H_J] = {
+ .name = "WinFast DTV2000 H rev. J",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00017300,
+ .gpio1 = 0x00008207,
+ .gpio2 = 0x00000000,
+ .gpio3 = 0x02000000,
+ },{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00018300,
+ .gpio1 = 0x0000f207,
+ .gpio2 = 0x00017304,
+ .gpio3 = 0x02000000,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x00018301,
+ .gpio1 = 0x0000f207,
+ .gpio2 = 0x00017304,
+ .gpio3 = 0x02000000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x00018301,
+ .gpio1 = 0x0000f207,
+ .gpio2 = 0x00017304,
+ .gpio3 = 0x02000000,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x00015702,
+ .gpio1 = 0x0000f207,
+ .gpio2 = 0x00015702,
+ .gpio3 = 0x02000000,
+ },
+ .mpeg = CX88_MPEG_DVB,
+ },
[CX88_BOARD_GENIATECH_DVBS] = {
.name = "Geniatech DVB-S",
.tuner_type = TUNER_ABSENT,
@@ -1908,7 +1953,8 @@ static const struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_DVB,
- .vmux = 1,
+ .vmux = 0,
+ .gpio0 = 0x8080,
} },
.mpeg = CX88_MPEG_DVB,
},
@@ -2282,6 +2328,10 @@ static const struct cx88_subid cx88_subids[] = {
.subdevice = 0x665e,
.card = CX88_BOARD_WINFAST_DTV2000H,
},{
+ .subvendor = 0x107d,
+ .subdevice = 0x6f2b,
+ .card = CX88_BOARD_WINFAST_DTV2000H_J,
+ },{
.subvendor = 0x18ac,
.subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
.card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
@@ -3162,7 +3212,11 @@ static void cx88_card_setup(struct cx88_core *core)
case CX88_BOARD_PROF_6200:
case CX88_BOARD_PROF_7300:
case CX88_BOARD_SATTRADE_ST4200:
+ cx_write(MO_GP0_IO, 0x8000);
+ msleep(100);
cx_write(MO_SRST_IO, 0);
+ msleep(10);
+ cx_write(MO_GP0_IO, 0x8080);
msleep(100);
cx_write(MO_SRST_IO, 1);
msleep(100);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index e237b507659b..6e5d142b5b00 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -424,17 +424,16 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
+ cx_set(MO_GP0_IO, 0x6040);
switch (voltage) {
case SEC_VOLTAGE_13:
- printk("LNB Voltage SEC_VOLTAGE_13\n");
- cx_write(MO_GP0_IO, 0x00006040);
+ cx_clear(MO_GP0_IO, 0x20);
break;
case SEC_VOLTAGE_18:
- printk("LNB Voltage SEC_VOLTAGE_18\n");
- cx_write(MO_GP0_IO, 0x00006060);
+ cx_set(MO_GP0_IO, 0x20);
break;
case SEC_VOLTAGE_OFF:
- printk("LNB Voltage SEC_VOLTAGE_off\n");
+ cx_clear(MO_GP0_IO, 0x20);
break;
}
@@ -499,9 +498,9 @@ static struct zl10353_config cx88_pinnacle_hybrid_pctv = {
};
static struct zl10353_config cx88_geniatech_x8000_mt = {
- .demod_address = (0x1e >> 1),
- .no_tuner = 1,
- .disable_i2c_gate_ctrl = 1,
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .disable_i2c_gate_ctrl = 1,
};
static struct s5h1411_config dvico_fusionhdtv7_config = {
@@ -696,6 +695,7 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
+ case CX88_BOARD_WINFAST_DTV2000H_J:
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
case CX88_BOARD_HAUPPAUGE_HVR1300:
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index d91f5c51206d..79c4408a6171 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -23,7 +23,7 @@
*/
#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/hrtimer.h>
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/module.h>
@@ -48,7 +48,7 @@ struct cx88_IR {
/* poll external decoder */
int polling;
- struct delayed_work work;
+ struct hrtimer timer;
u32 gpio_addr;
u32 last_gpio;
u32 mask_keycode;
@@ -144,19 +144,28 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
}
}
-static void cx88_ir_work(struct work_struct *work)
+static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
{
- struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work);
+ unsigned long missed;
+ struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
cx88_ir_handle_key(ir);
- schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+ missed = hrtimer_forward_now(&ir->timer,
+ ktime_set(0, ir->polling * 1000000));
+ if (missed > 1)
+ ir_dprintk("Missed ticks %ld\n", missed - 1);
+
+ return HRTIMER_RESTART;
}
void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
- INIT_DELAYED_WORK(&ir->work, cx88_ir_work);
- schedule_delayed_work(&ir->work, 0);
+ hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ir->timer.function = cx88_ir_work;
+ hrtimer_start(&ir->timer,
+ ktime_set(0, ir->polling * 1000000),
+ HRTIMER_MODE_REL);
}
if (ir->sampling) {
core->pci_irqmask |= PCI_INT_IR_SMPINT;
@@ -173,7 +182,7 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
}
if (ir->polling)
- cancel_delayed_work_sync(&ir->work);
+ hrtimer_cancel(&ir->timer);
}
/* ---------------------------------------------------------------------- */
@@ -225,6 +234,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->sampling = 1;
break;
case CX88_BOARD_WINFAST_DTV2000H:
+ case CX88_BOARD_WINFAST_DTV2000H_J:
case CX88_BOARD_WINFAST_DTV1800H:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 9d83762163f5..d5cea41f4207 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -237,6 +237,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
#define CX88_BOARD_HAUPPAUGE_IRONLY 80
#define CX88_BOARD_WINFAST_DTV1800H 81
+#define CX88_BOARD_WINFAST_DTV2000H_J 82
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile
new file mode 100644
index 000000000000..f44cad2f5412
--- /dev/null
+++ b/drivers/media/video/davinci/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the davinci video device drivers.
+#
+
+# VPIF
+obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o
+
+#DM646x EVM Display driver
+obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o
+
+# Capture: DM6446 and DM355
+obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o
+obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
+obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
+obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
diff --git a/drivers/media/video/davinci/ccdc_hw_device.h b/drivers/media/video/davinci/ccdc_hw_device.h
new file mode 100644
index 000000000000..86b9b3518965
--- /dev/null
+++ b/drivers/media/video/davinci/ccdc_hw_device.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * ccdc device API
+ */
+#ifndef _CCDC_HW_DEVICE_H
+#define _CCDC_HW_DEVICE_H
+
+#ifdef __KERNEL__
+#include <linux/videodev2.h>
+#include <linux/device.h>
+#include <media/davinci/vpfe_types.h>
+#include <media/davinci/ccdc_types.h>
+
+/*
+ * ccdc hw operations
+ */
+struct ccdc_hw_ops {
+ /* Pointer to initialize function to initialize ccdc device */
+ int (*open) (struct device *dev);
+ /* Pointer to deinitialize function */
+ int (*close) (struct device *dev);
+ /* set ccdc base address */
+ void (*set_ccdc_base)(void *base, int size);
+ /* Pointer to function to enable or disable ccdc */
+ void (*enable) (int en);
+ /* reset sbl. only for 6446 */
+ void (*reset) (void);
+ /* enable output to sdram */
+ void (*enable_out_to_sdram) (int en);
+ /* Pointer to function to set hw parameters */
+ int (*set_hw_if_params) (struct vpfe_hw_if_param *param);
+ /* get interface parameters */
+ int (*get_hw_if_params) (struct vpfe_hw_if_param *param);
+ /*
+ * Pointer to function to set parameters. Used
+ * for implementing VPFE_S_CCDC_PARAMS
+ */
+ int (*set_params) (void *params);
+ /*
+ * Pointer to function to get parameter. Used
+ * for implementing VPFE_G_CCDC_PARAMS
+ */
+ int (*get_params) (void *params);
+ /* Pointer to function to configure ccdc */
+ int (*configure) (void);
+
+ /* Pointer to function to set buffer type */
+ int (*set_buftype) (enum ccdc_buftype buf_type);
+ /* Pointer to function to get buffer type */
+ enum ccdc_buftype (*get_buftype) (void);
+ /* Pointer to function to set frame format */
+ int (*set_frame_format) (enum ccdc_frmfmt frm_fmt);
+ /* Pointer to function to get frame format */
+ enum ccdc_frmfmt (*get_frame_format) (void);
+ /* enumerate hw pix formats */
+ int (*enum_pix)(u32 *hw_pix, int i);
+ /* Pointer to function to set buffer type */
+ u32 (*get_pixel_format) (void);
+ /* Pointer to function to get pixel format. */
+ int (*set_pixel_format) (u32 pixfmt);
+ /* Pointer to function to set image window */
+ int (*set_image_window) (struct v4l2_rect *win);
+ /* Pointer to function to set image window */
+ void (*get_image_window) (struct v4l2_rect *win);
+ /* Pointer to function to get line length */
+ unsigned int (*get_line_length) (void);
+
+ /* Query CCDC control IDs */
+ int (*queryctrl)(struct v4l2_queryctrl *qctrl);
+ /* Set CCDC control */
+ int (*set_control)(struct v4l2_control *ctrl);
+ /* Get CCDC control */
+ int (*get_control)(struct v4l2_control *ctrl);
+
+ /* Pointer to function to set frame buffer address */
+ void (*setfbaddr) (unsigned long addr);
+ /* Pointer to function to get field id */
+ int (*getfid) (void);
+};
+
+struct ccdc_hw_device {
+ /* ccdc device name */
+ char name[32];
+ /* module owner */
+ struct module *owner;
+ /* hw ops */
+ struct ccdc_hw_ops hw_ops;
+};
+
+/* Used by CCDC module to register & unregister with vpfe capture driver */
+int vpfe_register_ccdc_device(struct ccdc_hw_device *dev);
+void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev);
+
+#endif
+#endif
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c
new file mode 100644
index 000000000000..4629cabe3f28
--- /dev/null
+++ b/drivers/media/video/davinci/dm355_ccdc.c
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * CCDC hardware module for DM355
+ * ------------------------------
+ *
+ * This module is for configuring DM355 CCD controller of VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application include dm355_ccdc.h and vpfe_capture.h header
+ * files. The setparams() API is called by vpfe_capture driver
+ * to configure module parameters
+ *
+ * TODO: 1) Raw bayer parameter settings and bayer capture
+ * 2) Split module parameter structure to module specific ioctl structs
+ * 3) add support for lense shading correction
+ * 4) investigate if enum used for user space type definition
+ * to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <media/davinci/dm355_ccdc.h>
+#include <media/davinci/vpss.h>
+#include "dm355_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM355");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct device *dev;
+
+/* Object for CCDC raw mode */
+static struct ccdc_params_raw ccdc_hw_params_raw = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .gain = {
+ .r_ye = 256,
+ .gb_g = 256,
+ .gr_cy = 256,
+ .b_mg = 256
+ },
+ .config_params = {
+ .datasft = 2,
+ .data_sz = CCDC_DATA_10BITS,
+ .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
+ .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
+ .alaw = {
+ .gama_wd = 2,
+ },
+ .blk_clamp = {
+ .sample_pixel = 1,
+ .dc_sub = 25
+ },
+ .col_pat_field0 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
+ .col_pat_field1 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
+ },
+};
+
+
+/* Object for CCDC ycbcr mode */
+static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
+ .win = CCDC_WIN_PAL,
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+};
+
+static enum vpfe_hw_if_type ccdc_if_type;
+static void *__iomem ccdc_base_addr;
+static int ccdc_addr_size;
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+ {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+ {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(ccdc_base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, ccdc_base_addr + offset);
+}
+
+static void ccdc_set_ccdc_base(void *addr, int size)
+{
+ ccdc_base_addr = addr;
+ ccdc_addr_size = size;
+}
+
+static void ccdc_enable(int en)
+{
+ unsigned int temp;
+ temp = regr(SYNCEN);
+ temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
+ temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
+ regw(temp, SYNCEN);
+}
+
+static void ccdc_enable_output_to_sdram(int en)
+{
+ unsigned int temp;
+ temp = regr(SYNCEN);
+ temp &= (~(CCDC_SYNCEN_WEN_MASK));
+ temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
+ regw(temp, SYNCEN);
+}
+
+static void ccdc_config_gain_offset(void)
+{
+ /* configure gain */
+ regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN);
+ regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN);
+ regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN);
+ regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN);
+ /* configure offset */
+ regw(ccdc_hw_params_raw.ccdc_offset, OFFSET);
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function restore power on defaults in the ccdc registers
+ */
+static int ccdc_restore_defaults(void)
+{
+ int i;
+
+ dev_dbg(dev, "\nstarting ccdc_restore_defaults...");
+ /* set all registers to zero */
+ for (i = 0; i <= CCDC_REG_LAST; i += 4)
+ regw(0, i);
+
+ /* now override the values with power on defaults in registers */
+ regw(MODESET_DEFAULT, MODESET);
+ /* no culling support */
+ regw(CULH_DEFAULT, CULH);
+ regw(CULV_DEFAULT, CULV);
+ /* Set default Gain and Offset */
+ ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT;
+ ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT;
+ ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT;
+ ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT;
+ ccdc_config_gain_offset();
+ regw(OUTCLIP_DEFAULT, OUTCLIP);
+ regw(LSCCFG2_DEFAULT, LSCCFG2);
+ /* select ccdc input */
+ if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
+ dev_dbg(dev, "\ncouldn't select ccdc input source");
+ return -EFAULT;
+ }
+ /* select ccdc clock */
+ if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
+ dev_dbg(dev, "\ncouldn't enable ccdc clock");
+ return -EFAULT;
+ }
+ dev_dbg(dev, "\nEnd of ccdc_restore_defaults...");
+ return 0;
+}
+
+static int ccdc_open(struct device *device)
+{
+ dev = device;
+ return ccdc_restore_defaults();
+}
+
+static int ccdc_close(struct device *device)
+{
+ /* disable clock */
+ vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
+ /* do nothing for now */
+ return 0;
+}
+/*
+ * ccdc_setwin()
+ * This function will configure the window size to
+ * be capture in CCDC reg.
+ */
+static void ccdc_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt, int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int mid_img = 0;
+
+ dev_dbg(dev, "\nStarting ccdc_setwin...");
+
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
+
+ /* Writing the horizontal info into the registers */
+ regw(horz_start, SPH);
+ regw(horz_nr_pixels, NPH);
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ /* configure VDINT0 and VDINT1 */
+ regw(vert_start, VDINT0);
+ } else {
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /* configure VDINT0 and VDINT1 */
+ mid_img = vert_start + (image_win->height / 2);
+ regw(vert_start, VDINT0);
+ regw(mid_img, VDINT1);
+ }
+ regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
+ regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
+ regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
+ dev_dbg(dev, "\nEnd of ccdc_setwin...");
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+ if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
+ ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
+ dev_dbg(dev, "Invalid value of data shift\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
+ ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
+ dev_dbg(dev, "Invalid value of median filter1\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
+ ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
+ dev_dbg(dev, "Invalid value of median filter2\n");
+ return -EINVAL;
+ }
+
+ if ((ccdcparam->med_filt_thres < 0) ||
+ (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
+ dev_dbg(dev, "Invalid value of median filter thresold\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
+ ccdcparam->data_sz > CCDC_DATA_8BITS) {
+ dev_dbg(dev, "Invalid value of data size\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->alaw.enable) {
+ if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
+ ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
+ dev_dbg(dev, "Invalid value of ALAW\n");
+ return -EINVAL;
+ }
+ }
+
+ if (ccdcparam->blk_clamp.b_clamp_enable) {
+ if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
+ ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
+ dev_dbg(dev, "Invalid value of sample pixel\n");
+ return -EINVAL;
+ }
+ if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
+ ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
+ dev_dbg(dev, "Invalid value of sample lines\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+ struct ccdc_config_params_raw ccdc_raw_params;
+ int x;
+
+ /* only raw module parameters can be set through the IOCTL */
+ if (ccdc_if_type != VPFE_RAW_BAYER)
+ return -EINVAL;
+
+ x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+ if (x) {
+ dev_dbg(dev, "ccdc_set_params: error in copying ccdc"
+ "params, %d\n", x);
+ return -EFAULT;
+ }
+
+ if (!validate_ccdc_param(&ccdc_raw_params)) {
+ memcpy(&ccdc_hw_params_raw.config_params,
+ &ccdc_raw_params,
+ sizeof(ccdc_raw_params));
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* This function will configure CCDC for YCbCr video capture */
+static void ccdc_config_ycbcr(void)
+{
+ struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
+ u32 temp;
+
+ /* first set the CCDC power on defaults values in all registers */
+ dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
+ ccdc_restore_defaults();
+
+ /* configure pixel format & video frame format */
+ temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
+ CCDC_INPUT_MODE_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
+ CCDC_FRM_FMT_SHIFT));
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ regw(CCDC_REC656IF_BT656_EN, REC656IF);
+ /*
+ * configure the FID, VD, HD pin polarity fld,hd pol positive,
+ * vd negative, 8-bit pack mode
+ */
+ temp |= CCDC_VD_POL_NEGATIVE;
+ } else { /* y/c external sync mode */
+ temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+ CCDC_FID_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) <<
+ CCDC_HD_POL_SHIFT) |
+ ((params->vd_pol & CCDC_VD_POL_MASK) <<
+ CCDC_VD_POL_SHIFT));
+ }
+
+ /* pack the data to 8-bit */
+ temp |= CCDC_DATA_PACK_ENABLE;
+
+ regw(temp, MODESET);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+ /* configure the order of y cb cr in SD-RAM */
+ temp = (params->pix_order << CCDC_Y8POS_SHIFT);
+ temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
+ regw(temp, CCDCFG);
+
+ /*
+ * configure the horizontal line offset. This is done by rounding up
+ * width to a multiple of 16 pixels and multiply by two to account for
+ * y:cb:cr 4:2:2 data
+ */
+ regw(((params->win.width * 2 + 31) >> 5), HSIZE);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+ /* two fields are interleaved in memory */
+ regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
+ }
+
+ dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
+}
+
+/*
+ * ccdc_config_black_clamp()
+ * configure parameters for Optical Black Clamp
+ */
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+ u32 val;
+
+ if (!bclamp->b_clamp_enable) {
+ /* configure DCSub */
+ regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
+ regw(0x0000, CLAMP);
+ return;
+ }
+ /* Enable the Black clamping, set sample lines and pixels */
+ val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
+ ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+ CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
+ regw(val, CLAMP);
+
+ /* If Black clamping is enable then make dcsub 0 */
+ val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
+ << CCDC_NUM_LINE_CALC_SHIFT;
+ regw(val, DCSUB);
+}
+
+/*
+ * ccdc_config_black_compense()
+ * configure parameters for Black Compensation
+ */
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+ u32 val;
+
+ val = (bcomp->b & CCDC_BLK_COMP_MASK) |
+ ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GB_COMP_SHIFT);
+ regw(val, BLKCMP1);
+
+ val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GR_COMP_SHIFT) |
+ ((bcomp->r & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_R_COMP_SHIFT);
+ regw(val, BLKCMP0);
+}
+
+/*
+ * ccdc_write_dfc_entry()
+ * write an entry in the dfc table.
+ */
+int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
+{
+/* TODO This is to be re-visited and adjusted */
+#define DFC_WRITE_WAIT_COUNT 1000
+ u32 val, count = DFC_WRITE_WAIT_COUNT;
+
+ regw(dfc->dft_corr_vert[index], DFCMEM0);
+ regw(dfc->dft_corr_horz[index], DFCMEM1);
+ regw(dfc->dft_corr_sub1[index], DFCMEM2);
+ regw(dfc->dft_corr_sub2[index], DFCMEM3);
+ regw(dfc->dft_corr_sub3[index], DFCMEM4);
+ /* set WR bit to write */
+ val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
+ regw(val, DFCMEMCTL);
+
+ /*
+ * Assume, it is very short. If we get an error, we need to
+ * adjust this value
+ */
+ while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
+ count--;
+ /*
+ * TODO We expect the count to be non-zero to be successful. Adjust
+ * the count if write requires more time
+ */
+
+ if (count) {
+ dev_err(dev, "defect table write timeout !!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * ccdc_config_vdfc()
+ * configure parameters for Vertical Defect Correction
+ */
+static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
+{
+ u32 val;
+ int i;
+
+ /* Configure General Defect Correction. The table used is from IPIPE */
+ val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
+
+ /* Configure Vertical Defect Correction if needed */
+ if (!dfc->ver_dft_en) {
+ /* Enable only General Defect Correction */
+ regw(val, DFCCTL);
+ return 0;
+ }
+
+ if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
+ return -EINVAL;
+
+ val |= CCDC_DFCCTL_VDFC_DISABLE;
+ val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
+ CCDC_DFCCTL_VDFCSL_SHIFT;
+ val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
+ CCDC_DFCCTL_VDFCUDA_SHIFT;
+ val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
+ CCDC_DFCCTL_VDFLSFT_SHIFT;
+ regw(val , DFCCTL);
+
+ /* clear address ptr to offset 0 */
+ val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
+
+ /* write defect table entries */
+ for (i = 0; i < dfc->table_size; i++) {
+ /* increment address for non zero index */
+ if (i != 0)
+ val = CCDC_DFCMEMCTL_INC_ADDR;
+ regw(val, DFCMEMCTL);
+ if (ccdc_write_dfc_entry(i, dfc) < 0)
+ return -EFAULT;
+ }
+
+ /* update saturation level and enable dfc */
+ regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
+ val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
+ CCDC_DFCCTL_VDFCEN_SHIFT);
+ regw(val, DFCCTL);
+ return 0;
+}
+
+/*
+ * ccdc_config_csc()
+ * configure parameters for color space conversion
+ * Each register CSCM0-7 has two values in S8Q5 format.
+ */
+static void ccdc_config_csc(struct ccdc_csc *csc)
+{
+ u32 val1, val2;
+ int i;
+
+ if (!csc->enable)
+ return;
+
+ /* Enable the CSC sub-module */
+ regw(CCDC_CSC_ENABLE, CSCCTL);
+
+ /* Converting the co-eff as per the format of the register */
+ for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
+ if ((i % 2) == 0) {
+ /* CSCM - LSB */
+ val1 = (csc->coeff[i].integer &
+ CCDC_CSC_COEF_INTEG_MASK)
+ << CCDC_CSC_COEF_INTEG_SHIFT;
+ /*
+ * convert decimal part to binary. Use 2 decimal
+ * precision, user values range from .00 - 0.99
+ */
+ val1 |= (((csc->coeff[i].decimal &
+ CCDC_CSC_COEF_DECIMAL_MASK) *
+ CCDC_CSC_DEC_MAX) / 100);
+ } else {
+
+ /* CSCM - MSB */
+ val2 = (csc->coeff[i].integer &
+ CCDC_CSC_COEF_INTEG_MASK)
+ << CCDC_CSC_COEF_INTEG_SHIFT;
+ val2 |= (((csc->coeff[i].decimal &
+ CCDC_CSC_COEF_DECIMAL_MASK) *
+ CCDC_CSC_DEC_MAX) / 100);
+ val2 <<= CCDC_CSCM_MSB_SHIFT;
+ val2 |= val1;
+ regw(val2, (CSCM0 + ((i - 1) << 1)));
+ }
+ }
+}
+
+/*
+ * ccdc_config_color_patterns()
+ * configure parameters for color patterns
+ */
+static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
+ struct ccdc_col_pat *pat1)
+{
+ u32 val;
+
+ val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
+ (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
+ (pat1->elop << 12) | (pat1->elep << 14));
+ regw(val, COLPTN);
+}
+
+/* This function will configure CCDC for Raw mode image capture */
+static int ccdc_config_raw(void)
+{
+ struct ccdc_params_raw *params = &ccdc_hw_params_raw;
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int val;
+
+ dev_dbg(dev, "\nStarting ccdc_config_raw...");
+
+ /* restore power on defaults to register */
+ ccdc_restore_defaults();
+
+ /* CCDCFG register:
+ * set CCD Not to swap input since input is RAW data
+ * set FID detection function to Latch at V-Sync
+ * set WENLOG - ccdc valid area to AND
+ * set TRGSEL to WENBIT
+ * set EXTRG to DISABLE
+ * disable latching function on VSYNC - shadowed registers
+ */
+ regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
+ CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
+ CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
+
+ /*
+ * Set VDHD direction to input, input type to raw input
+ * normal data polarity, do not use external WEN
+ */
+ val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
+ CCDC_EXWEN_DISABLE);
+
+ /*
+ * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
+ * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
+ * frame format(progressive or interlace), & pixel format (Input mode)
+ */
+ val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+ ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+ ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
+
+ /* set pack for alaw compression */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ val |= CCDC_DATA_PACK_ENABLE;
+
+ /* Configure for LPF */
+ if (config_params->lpf_enable)
+ val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
+ CCDC_LPF_SHIFT;
+
+ /* Configure the data shift */
+ val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
+ CCDC_DATASFT_SHIFT;
+ regw(val , MODESET);
+ dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val);
+
+ /* Configure the Median Filter threshold */
+ regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
+
+ /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
+ val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
+ CCDC_CFA_MOSAIC;
+
+ /* Enable and configure aLaw register if needed */
+ if (config_params->alaw.enable) {
+ val |= (CCDC_ALAW_ENABLE |
+ ((config_params->alaw.gama_wd &
+ CCDC_ALAW_GAMA_WD_MASK) <<
+ CCDC_GAMMAWD_INPUT_SHIFT));
+ }
+
+ /* Configure Median filter1 & filter2 */
+ val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
+ (config_params->mfilt2 << CCDC_MFILT2_SHIFT));
+
+ regw(val, GAMMAWD);
+ dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 1);
+
+ /* Optical Clamp Averaging */
+ ccdc_config_black_clamp(&config_params->blk_clamp);
+
+ /* Black level compensation */
+ ccdc_config_black_compense(&config_params->blk_comp);
+
+ /* Vertical Defect Correction if needed */
+ if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
+ return -EFAULT;
+
+ /* color space conversion */
+ ccdc_config_csc(&config_params->csc);
+
+ /* color pattern */
+ ccdc_config_color_patterns(&config_params->col_pat_field0,
+ &config_params->col_pat_field1);
+
+ /* Configure the Gain & offset control */
+ ccdc_config_gain_offset();
+
+ dev_dbg(dev, "\nWriting %x to COLPTN...\n", val);
+
+ /* Configure DATAOFST register */
+ val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
+ CCDC_DATAOFST_H_SHIFT;
+ val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
+ CCDC_DATAOFST_V_SHIFT;
+ regw(val, DATAOFST);
+
+ /* configuring HSIZE register */
+ val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
+ CCDC_HSIZE_FLIP_SHIFT;
+
+ /* If pack 8 is enable then 1 pixel will take 1 byte */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable) {
+ val |= (((params->win.width) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK;
+
+ /* adjust to multiple of 32 */
+ dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
+ (((params->win.width) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK);
+ } else {
+ /* else one pixel will take 2 byte */
+ val |= (((params->win.width * 2) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK;
+
+ dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
+ (((params->win.width * 2) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK);
+ }
+ regw(val, HSIZE);
+
+ /* Configure SDOFST register */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_enable) {
+ /* For interlace inverse mode */
+ regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_INTERLACE_INVERSE);
+ } else {
+ /* For interlace non inverse mode */
+ regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_INTERLACE_NORMAL);
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ if (params->image_invert_enable) {
+ /* For progessive inverse mode */
+ regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_PROGRESSIVE_INVERSE);
+ } else {
+ /* For progessive non inverse mode */
+ regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_PROGRESSIVE_NORMAL);
+ }
+ }
+ dev_dbg(dev, "\nend of ccdc_config_raw...");
+ return 0;
+}
+
+static int ccdc_configure(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_config_raw();
+ else
+ ccdc_config_ycbcr();
+ return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.buf_type = buf_type;
+ else
+ ccdc_hw_params_ycbcr.buf_type = buf_type;
+ return 0;
+}
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.buf_type;
+ return ccdc_hw_params_ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+ *pix = ccdc_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+ *pix = ccdc_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+ struct ccdc_a_law *alaw =
+ &ccdc_hw_params_raw.config_params.alaw;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+ alaw->enable = 1;
+ else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+ return -EINVAL;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+static u32 ccdc_get_pixel_format(void)
+{
+ struct ccdc_a_law *alaw =
+ &ccdc_hw_params_raw.config_params.alaw;
+ u32 pixfmt;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (alaw->enable)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.win = *win;
+ else
+ ccdc_hw_params_ycbcr.win = *win;
+ return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ *win = ccdc_hw_params_raw.win;
+ else
+ *win = ccdc_hw_params_ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int len;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if ((config_params->alaw.enable) ||
+ (config_params->data_sz == CCDC_DATA_8BITS))
+ len = ccdc_hw_params_raw.win.width;
+ else
+ len = ccdc_hw_params_raw.win.width * 2;
+ } else
+ len = ccdc_hw_params_ycbcr.win.width * 2;
+ return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.frm_fmt = frm_fmt;
+ else
+ ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.frm_fmt;
+ else
+ return ccdc_hw_params_ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+ return (regr(MODESET) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+ regw((addr >> 21) & 0x007f, STADRH);
+ regw((addr >> 5) & 0x0ffff, STADRL);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ ccdc_if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_YCBCR_SYNC_16:
+ case VPFE_YCBCR_SYNC_8:
+ ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
+ ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
+ break;
+ default:
+ /* TODO add support for raw bayer here */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct ccdc_hw_device ccdc_hw_dev = {
+ .name = "DM355 CCDC",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = ccdc_open,
+ .close = ccdc_close,
+ .set_ccdc_base = ccdc_set_ccdc_base,
+ .enable = ccdc_enable,
+ .enable_out_to_sdram = ccdc_enable_output_to_sdram,
+ .set_hw_if_params = ccdc_set_hw_if_params,
+ .set_params = ccdc_set_params,
+ .configure = ccdc_configure,
+ .set_buftype = ccdc_set_buftype,
+ .get_buftype = ccdc_get_buftype,
+ .enum_pix = ccdc_enum_pix,
+ .set_pixel_format = ccdc_set_pixel_format,
+ .get_pixel_format = ccdc_get_pixel_format,
+ .set_frame_format = ccdc_set_frame_format,
+ .get_frame_format = ccdc_get_frame_format,
+ .set_image_window = ccdc_set_image_window,
+ .get_image_window = ccdc_get_image_window,
+ .get_line_length = ccdc_get_line_length,
+ .setfbaddr = ccdc_setfbaddr,
+ .getfid = ccdc_getfid,
+ },
+};
+
+static int dm355_ccdc_init(void)
+{
+ printk(KERN_NOTICE "dm355_ccdc_init\n");
+ if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
+ return -1;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n",
+ ccdc_hw_dev.name);
+ return 0;
+}
+
+static void dm355_ccdc_exit(void)
+{
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+}
+
+module_init(dm355_ccdc_init);
+module_exit(dm355_ccdc_exit);
diff --git a/drivers/media/video/davinci/dm355_ccdc_regs.h b/drivers/media/video/davinci/dm355_ccdc_regs.h
new file mode 100644
index 000000000000..d6d2ef0533b5
--- /dev/null
+++ b/drivers/media/video/davinci/dm355_ccdc_regs.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * 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
+ */
+#ifndef _DM355_CCDC_REGS_H
+#define _DM355_CCDC_REGS_H
+
+/**************************************************************************\
+* Register OFFSET Definitions
+\**************************************************************************/
+#define SYNCEN 0x00
+#define MODESET 0x04
+#define HDWIDTH 0x08
+#define VDWIDTH 0x0c
+#define PPLN 0x10
+#define LPFR 0x14
+#define SPH 0x18
+#define NPH 0x1c
+#define SLV0 0x20
+#define SLV1 0x24
+#define NLV 0x28
+#define CULH 0x2c
+#define CULV 0x30
+#define HSIZE 0x34
+#define SDOFST 0x38
+#define STADRH 0x3c
+#define STADRL 0x40
+#define CLAMP 0x44
+#define DCSUB 0x48
+#define COLPTN 0x4c
+#define BLKCMP0 0x50
+#define BLKCMP1 0x54
+#define MEDFILT 0x58
+#define RYEGAIN 0x5c
+#define GRCYGAIN 0x60
+#define GBGGAIN 0x64
+#define BMGGAIN 0x68
+#define OFFSET 0x6c
+#define OUTCLIP 0x70
+#define VDINT0 0x74
+#define VDINT1 0x78
+#define RSV0 0x7c
+#define GAMMAWD 0x80
+#define REC656IF 0x84
+#define CCDCFG 0x88
+#define FMTCFG 0x8c
+#define FMTPLEN 0x90
+#define FMTSPH 0x94
+#define FMTLNH 0x98
+#define FMTSLV 0x9c
+#define FMTLNV 0xa0
+#define FMTRLEN 0xa4
+#define FMTHCNT 0xa8
+#define FMT_ADDR_PTR_B 0xac
+#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4))
+#define FMTPGM_VF0 0xcc
+#define FMTPGM_VF1 0xd0
+#define FMTPGM_AP0 0xd4
+#define FMTPGM_AP1 0xd8
+#define FMTPGM_AP2 0xdc
+#define FMTPGM_AP3 0xe0
+#define FMTPGM_AP4 0xe4
+#define FMTPGM_AP5 0xe8
+#define FMTPGM_AP6 0xec
+#define FMTPGM_AP7 0xf0
+#define LSCCFG1 0xf4
+#define LSCCFG2 0xf8
+#define LSCH0 0xfc
+#define LSCV0 0x100
+#define LSCKH 0x104
+#define LSCKV 0x108
+#define LSCMEMCTL 0x10c
+#define LSCMEMD 0x110
+#define LSCMEMQ 0x114
+#define DFCCTL 0x118
+#define DFCVSAT 0x11c
+#define DFCMEMCTL 0x120
+#define DFCMEM0 0x124
+#define DFCMEM1 0x128
+#define DFCMEM2 0x12c
+#define DFCMEM3 0x130
+#define DFCMEM4 0x134
+#define CSCCTL 0x138
+#define CSCM0 0x13c
+#define CSCM1 0x140
+#define CSCM2 0x144
+#define CSCM3 0x148
+#define CSCM4 0x14c
+#define CSCM5 0x150
+#define CSCM6 0x154
+#define CSCM7 0x158
+#define DATAOFST 0x15c
+#define CCDC_REG_LAST DATAOFST
+/**************************************************************
+* Define for various register bit mask and shifts for CCDC
+*
+**************************************************************/
+#define CCDC_RAW_IP_MODE 0
+#define CCDC_VDHDOUT_INPUT 0
+#define CCDC_YCINSWP_RAW (0 << 4)
+#define CCDC_EXWEN_DISABLE 0
+#define CCDC_DATAPOL_NORMAL 0
+#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0
+#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6)
+#define CCDC_CCDCFG_WENLOG_AND 0
+#define CCDC_CCDCFG_TRGSEL_WEN 0
+#define CCDC_CCDCFG_EXTRG_DISABLE 0
+#define CCDC_CFA_MOSAIC 0
+#define CCDC_Y8POS_SHIFT 11
+
+#define CCDC_VDC_DFCVSAT_MASK 0x3fff
+#define CCDC_DATAOFST_MASK 0x0ff
+#define CCDC_DATAOFST_H_SHIFT 0
+#define CCDC_DATAOFST_V_SHIFT 8
+#define CCDC_GAMMAWD_CFA_MASK 1
+#define CCDC_GAMMAWD_CFA_SHIFT 5
+#define CCDC_GAMMAWD_INPUT_SHIFT 2
+#define CCDC_FID_POL_MASK 1
+#define CCDC_FID_POL_SHIFT 4
+#define CCDC_HD_POL_MASK 1
+#define CCDC_HD_POL_SHIFT 3
+#define CCDC_VD_POL_MASK 1
+#define CCDC_VD_POL_SHIFT 2
+#define CCDC_VD_POL_NEGATIVE (1 << 2)
+#define CCDC_FRM_FMT_MASK 1
+#define CCDC_FRM_FMT_SHIFT 7
+#define CCDC_DATA_SZ_MASK 7
+#define CCDC_DATA_SZ_SHIFT 8
+#define CCDC_VDHDOUT_MASK 1
+#define CCDC_VDHDOUT_SHIFT 0
+#define CCDC_EXWEN_MASK 1
+#define CCDC_EXWEN_SHIFT 5
+#define CCDC_INPUT_MODE_MASK 3
+#define CCDC_INPUT_MODE_SHIFT 12
+#define CCDC_PIX_FMT_MASK 3
+#define CCDC_PIX_FMT_SHIFT 12
+#define CCDC_DATAPOL_MASK 1
+#define CCDC_DATAPOL_SHIFT 6
+#define CCDC_WEN_ENABLE (1 << 1)
+#define CCDC_VDHDEN_ENABLE (1 << 16)
+#define CCDC_LPF_ENABLE (1 << 14)
+#define CCDC_ALAW_ENABLE 1
+#define CCDC_ALAW_GAMA_WD_MASK 7
+#define CCDC_REC656IF_BT656_EN 3
+
+#define CCDC_FMTCFG_FMTMODE_MASK 3
+#define CCDC_FMTCFG_FMTMODE_SHIFT 1
+#define CCDC_FMTCFG_LNUM_MASK 3
+#define CCDC_FMTCFG_LNUM_SHIFT 4
+#define CCDC_FMTCFG_ADDRINC_MASK 7
+#define CCDC_FMTCFG_ADDRINC_SHIFT 8
+
+#define CCDC_CCDCFG_FIDMD_SHIFT 6
+#define CCDC_CCDCFG_WENLOG_SHIFT 8
+#define CCDC_CCDCFG_TRGSEL_SHIFT 9
+#define CCDC_CCDCFG_EXTRG_SHIFT 10
+#define CCDC_CCDCFG_MSBINVI_SHIFT 13
+
+#define CCDC_HSIZE_FLIP_SHIFT 12
+#define CCDC_HSIZE_FLIP_MASK 1
+#define CCDC_HSIZE_VAL_MASK 0xFFF
+#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249
+#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D
+#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D
+#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000
+#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0
+#define CCDC_START_PX_HOR_MASK 0x7FFF
+#define CCDC_NUM_PX_HOR_MASK 0x7FFF
+#define CCDC_START_VER_ONE_MASK 0x7FFF
+#define CCDC_START_VER_TWO_MASK 0x7FFF
+#define CCDC_NUM_LINES_VER 0x7FFF
+
+#define CCDC_BLK_CLAMP_ENABLE (1 << 15)
+#define CCDC_BLK_SGAIN_MASK 0x1F
+#define CCDC_BLK_ST_PXL_MASK 0x1FFF
+#define CCDC_BLK_SAMPLE_LN_MASK 3
+#define CCDC_BLK_SAMPLE_LN_SHIFT 13
+
+#define CCDC_NUM_LINE_CALC_MASK 3
+#define CCDC_NUM_LINE_CALC_SHIFT 14
+
+#define CCDC_BLK_DC_SUB_MASK 0x3FFF
+#define CCDC_BLK_COMP_MASK 0xFF
+#define CCDC_BLK_COMP_GB_COMP_SHIFT 8
+#define CCDC_BLK_COMP_GR_COMP_SHIFT 0
+#define CCDC_BLK_COMP_R_COMP_SHIFT 8
+#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15)
+#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15)
+#define CCDC_FPC_ENABLE (1 << 15)
+#define CCDC_FPC_FPC_NUM_MASK 0x7FFF
+#define CCDC_DATA_PACK_ENABLE (1 << 11)
+#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16
+#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_SHIFT 16
+#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF
+#define CCDC_VP_OUT_VERT_NUM_SHIFT 17
+#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF
+#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4
+#define CCDC_VP_OUT_HORZ_ST_MASK 0xF
+
+#define CCDC_CSC_COEF_INTEG_MASK 7
+#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f
+#define CCDC_CSC_COEF_INTEG_SHIFT 5
+#define CCDC_CSCM_MSB_SHIFT 8
+#define CCDC_CSC_ENABLE 1
+#define CCDC_CSC_DEC_MAX 32
+
+#define CCDC_MFILT1_SHIFT 10
+#define CCDC_MFILT2_SHIFT 8
+#define CCDC_MED_FILT_THRESH 0x3FFF
+#define CCDC_LPF_MASK 1
+#define CCDC_LPF_SHIFT 14
+#define CCDC_OFFSET_MASK 0x3FF
+#define CCDC_DATASFT_MASK 7
+#define CCDC_DATASFT_SHIFT 8
+
+#define CCDC_DF_ENABLE 1
+
+#define CCDC_FMTPLEN_P0_MASK 0xF
+#define CCDC_FMTPLEN_P1_MASK 0xF
+#define CCDC_FMTPLEN_P2_MASK 7
+#define CCDC_FMTPLEN_P3_MASK 7
+#define CCDC_FMTPLEN_P0_SHIFT 0
+#define CCDC_FMTPLEN_P1_SHIFT 4
+#define CCDC_FMTPLEN_P2_SHIFT 8
+#define CCDC_FMTPLEN_P3_SHIFT 12
+
+#define CCDC_FMTSPH_MASK 0x1FFF
+#define CCDC_FMTLNH_MASK 0x1FFF
+#define CCDC_FMTSLV_MASK 0x1FFF
+#define CCDC_FMTLNV_MASK 0x7FFF
+#define CCDC_FMTRLEN_MASK 0x1FFF
+#define CCDC_FMTHCNT_MASK 0x1FFF
+
+#define CCDC_ADP_INIT_MASK 0x1FFF
+#define CCDC_ADP_LINE_SHIFT 13
+#define CCDC_ADP_LINE_MASK 3
+#define CCDC_FMTPGN_APTR_MASK 7
+
+#define CCDC_DFCCTL_GDFCEN_MASK 1
+#define CCDC_DFCCTL_VDFCEN_MASK 1
+#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4)
+#define CCDC_DFCCTL_VDFCEN_SHIFT 4
+#define CCDC_DFCCTL_VDFCSL_MASK 3
+#define CCDC_DFCCTL_VDFCSL_SHIFT 5
+#define CCDC_DFCCTL_VDFCUDA_MASK 1
+#define CCDC_DFCCTL_VDFCUDA_SHIFT 7
+#define CCDC_DFCCTL_VDFLSFT_MASK 3
+#define CCDC_DFCCTL_VDFLSFT_SHIFT 8
+#define CCDC_DFCMEMCTL_DFCMARST_MASK 1
+#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2
+#define CCDC_DFCMEMCTL_DFCMWR_MASK 1
+#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0
+#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2)
+
+#define CCDC_LSCCFG_GFTSF_MASK 7
+#define CCDC_LSCCFG_GFTSF_SHIFT 1
+#define CCDC_LSCCFG_GFTINV_MASK 0xf
+#define CCDC_LSCCFG_GFTINV_SHIFT 4
+#define CCDC_LSC_GFTABLE_SEL_MASK 3
+#define CCDC_LSC_GFTABLE_EPEL_SHIFT 8
+#define CCDC_LSC_GFTABLE_OPEL_SHIFT 10
+#define CCDC_LSC_GFTABLE_EPOL_SHIFT 12
+#define CCDC_LSC_GFTABLE_OPOL_SHIFT 14
+#define CCDC_LSC_GFMODE_MASK 3
+#define CCDC_LSC_GFMODE_SHIFT 4
+#define CCDC_LSC_DISABLE 0
+#define CCDC_LSC_ENABLE 1
+#define CCDC_LSC_TABLE1_SLC 0
+#define CCDC_LSC_TABLE2_SLC 1
+#define CCDC_LSC_TABLE3_SLC 2
+#define CCDC_LSC_MEMADDR_RESET (1 << 2)
+#define CCDC_LSC_MEMADDR_INCR (0 << 2)
+#define CCDC_LSC_FRAC_MASK_T1 0xFF
+#define CCDC_LSC_INT_MASK 3
+#define CCDC_LSC_FRAC_MASK 0x3FFF
+#define CCDC_LSC_CENTRE_MASK 0x3FFF
+#define CCDC_LSC_COEF_MASK 0xff
+#define CCDC_LSC_COEFL_SHIFT 0
+#define CCDC_LSC_COEFU_SHIFT 8
+#define CCDC_GAIN_MASK 0x7FF
+#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0)
+#define CCDC_SYNCEN_WEN_MASK (1 << 1)
+#define CCDC_SYNCEN_WEN_SHIFT 1
+
+/* Power on Defaults in hardware */
+#define MODESET_DEFAULT 0x200
+#define CULH_DEFAULT 0xFFFF
+#define CULV_DEFAULT 0xFF
+#define GAIN_DEFAULT 256
+#define OUTCLIP_DEFAULT 0x3FFF
+#define LSCCFG2_DEFAULT 0xE
+
+#endif
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
new file mode 100644
index 000000000000..2f19a919f477
--- /dev/null
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -0,0 +1,878 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * CCDC hardware module for DM6446
+ * ------------------------------
+ *
+ * This module is for configuring CCD controller of DM6446 VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header
+ * files. The setparams() API is called by vpfe_capture driver
+ * to configure module parameters. This file is named DM644x so that other
+ * variants such DM6443 may be supported using the same module.
+ *
+ * TODO: Test Raw bayer parameter settings and bayer capture
+ * Split module parameter structure to module specific ioctl structs
+ * investigate if enum used for user space type definition
+ * to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <media/davinci/dm644x_ccdc.h>
+#include <media/davinci/vpss.h>
+#include "dm644x_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM6446");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct device *dev;
+
+/* Object for CCDC raw mode */
+static struct ccdc_params_raw ccdc_hw_params_raw = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .config_params = {
+ .data_sz = CCDC_DATA_10BITS,
+ },
+};
+
+/* Object for CCDC ycbcr mode */
+static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .win = CCDC_WIN_PAL,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+};
+
+#define CCDC_MAX_RAW_YUV_FORMATS 2
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+ {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+ {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+static void *__iomem ccdc_base_addr;
+static int ccdc_addr_size;
+static enum vpfe_hw_if_type ccdc_if_type;
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(ccdc_base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, ccdc_base_addr + offset);
+}
+
+static void ccdc_set_ccdc_base(void *addr, int size)
+{
+ ccdc_base_addr = addr;
+ ccdc_addr_size = size;
+}
+
+static void ccdc_enable(int flag)
+{
+ regw(flag, CCDC_PCR);
+}
+
+static void ccdc_enable_vport(int flag)
+{
+ if (flag)
+ /* enable video port */
+ regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
+ else
+ regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
+}
+
+/*
+ * ccdc_setwin()
+ * This function will configure the window size
+ * to be capture in CCDC reg
+ */
+void ccdc_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt,
+ int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int val = 0, mid_img = 0;
+
+ dev_dbg(dev, "\nStarting ccdc_setwin...");
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
+ regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
+ CCDC_HORZ_INFO);
+
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ /* configure VDINT0 */
+ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
+ regw(val, CCDC_VDINT);
+
+ } else {
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /*
+ * configure VDINT0 and VDINT1. VDINT1 will be at half
+ * of image height
+ */
+ mid_img = vert_start + (image_win->height / 2);
+ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
+ (mid_img & CCDC_VDINT_VDINT1_MASK);
+ regw(val, CCDC_VDINT);
+
+ }
+ regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
+ CCDC_VERT_START);
+ regw(vert_nr_lines, CCDC_VERT_LINES);
+ dev_dbg(dev, "\nEnd of ccdc_setwin...");
+}
+
+static void ccdc_readregs(void)
+{
+ unsigned int val = 0;
+
+ val = regr(CCDC_ALAW);
+ dev_notice(dev, "\nReading 0x%x to ALAW...\n", val);
+ val = regr(CCDC_CLAMP);
+ dev_notice(dev, "\nReading 0x%x to CLAMP...\n", val);
+ val = regr(CCDC_DCSUB);
+ dev_notice(dev, "\nReading 0x%x to DCSUB...\n", val);
+ val = regr(CCDC_BLKCMP);
+ dev_notice(dev, "\nReading 0x%x to BLKCMP...\n", val);
+ val = regr(CCDC_FPC_ADDR);
+ dev_notice(dev, "\nReading 0x%x to FPC_ADDR...\n", val);
+ val = regr(CCDC_FPC);
+ dev_notice(dev, "\nReading 0x%x to FPC...\n", val);
+ val = regr(CCDC_FMTCFG);
+ dev_notice(dev, "\nReading 0x%x to FMTCFG...\n", val);
+ val = regr(CCDC_COLPTN);
+ dev_notice(dev, "\nReading 0x%x to COLPTN...\n", val);
+ val = regr(CCDC_FMT_HORZ);
+ dev_notice(dev, "\nReading 0x%x to FMT_HORZ...\n", val);
+ val = regr(CCDC_FMT_VERT);
+ dev_notice(dev, "\nReading 0x%x to FMT_VERT...\n", val);
+ val = regr(CCDC_HSIZE_OFF);
+ dev_notice(dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
+ val = regr(CCDC_SDOFST);
+ dev_notice(dev, "\nReading 0x%x to SDOFST...\n", val);
+ val = regr(CCDC_VP_OUT);
+ dev_notice(dev, "\nReading 0x%x to VP_OUT...\n", val);
+ val = regr(CCDC_SYN_MODE);
+ dev_notice(dev, "\nReading 0x%x to SYN_MODE...\n", val);
+ val = regr(CCDC_HORZ_INFO);
+ dev_notice(dev, "\nReading 0x%x to HORZ_INFO...\n", val);
+ val = regr(CCDC_VERT_START);
+ dev_notice(dev, "\nReading 0x%x to VERT_START...\n", val);
+ val = regr(CCDC_VERT_LINES);
+ dev_notice(dev, "\nReading 0x%x to VERT_LINES...\n", val);
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+ if (ccdcparam->alaw.enable) {
+ if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
+ (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
+ (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
+ dev_dbg(dev, "\nInvalid data line select");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int *fpc_virtaddr = NULL;
+ unsigned int *fpc_physaddr = NULL;
+
+ memcpy(config_params, raw_params, sizeof(*raw_params));
+ /*
+ * allocate memory for fault pixel table and copy the user
+ * values to the table
+ */
+ if (!config_params->fault_pxl.enable)
+ return 0;
+
+ fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+ fpc_virtaddr = (unsigned int *)phys_to_virt(
+ (unsigned long)fpc_physaddr);
+ /*
+ * Allocate memory for FPC table if current
+ * FPC table buffer is not big enough to
+ * accomodate FPC Number requested
+ */
+ if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
+ if (fpc_physaddr != NULL) {
+ free_pages((unsigned long)fpc_physaddr,
+ get_order
+ (config_params->fault_pxl.fp_num *
+ FP_NUM_BYTES));
+ }
+
+ /* Allocate memory for FPC table */
+ fpc_virtaddr =
+ (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,
+ get_order(raw_params->
+ fault_pxl.fp_num *
+ FP_NUM_BYTES));
+
+ if (fpc_virtaddr == NULL) {
+ dev_dbg(dev,
+ "\nUnable to allocate memory for FPC");
+ return -EFAULT;
+ }
+ fpc_physaddr =
+ (unsigned int *)virt_to_phys((void *)fpc_virtaddr);
+ }
+
+ /* Copy number of fault pixels and FPC table */
+ config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;
+ if (copy_from_user(fpc_virtaddr,
+ (void __user *)raw_params->fault_pxl.fpc_table_addr,
+ config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
+ dev_dbg(dev, "\n copy_from_user failed");
+ return -EFAULT;
+ }
+ config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
+ return 0;
+}
+
+static int ccdc_close(struct device *dev)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
+
+ fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+
+ if (fpc_physaddr != NULL) {
+ fpc_virtaddr = (unsigned int *)
+ phys_to_virt((unsigned long)fpc_physaddr);
+ free_pages((unsigned long)fpc_virtaddr,
+ get_order(config_params->fault_pxl.fp_num *
+ FP_NUM_BYTES));
+ }
+ return 0;
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function will write defaults to all CCDC registers
+ */
+static void ccdc_restore_defaults(void)
+{
+ int i;
+
+ /* disable CCDC */
+ ccdc_enable(0);
+ /* set all registers to default value */
+ for (i = 4; i <= 0x94; i += 4)
+ regw(0, i);
+ regw(CCDC_NO_CULLING, CCDC_CULLING);
+ regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
+}
+
+static int ccdc_open(struct device *device)
+{
+ dev = device;
+ ccdc_restore_defaults();
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_enable_vport(1);
+ return 0;
+}
+
+static void ccdc_sbl_reset(void)
+{
+ vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+ struct ccdc_config_params_raw ccdc_raw_params;
+ int x;
+
+ if (ccdc_if_type != VPFE_RAW_BAYER)
+ return -EINVAL;
+
+ x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+ if (x) {
+ dev_dbg(dev, "ccdc_set_params: error in copying"
+ "ccdc params, %d\n", x);
+ return -EFAULT;
+ }
+
+ if (!validate_ccdc_param(&ccdc_raw_params)) {
+ if (!ccdc_update_raw_params(&ccdc_raw_params))
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/*
+ * ccdc_config_ycbcr()
+ * This function will configure CCDC for YCbCr video capture
+ */
+void ccdc_config_ycbcr(void)
+{
+ struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
+ u32 syn_mode;
+
+ dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
+ /*
+ * first restore the CCDC registers to default values
+ * This is important since we assume default values to be set in
+ * a lot of registers that we didn't touch
+ */
+ ccdc_restore_defaults();
+
+ /*
+ * configure pixel format, frame format, configure video frame
+ * format, enable output to SDRAM, enable internal timing generator
+ * and 8bit pack mode
+ */
+ syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
+ CCDC_SYN_MODE_INPMOD_SHIFT) |
+ ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
+ CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
+ CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
+
+ /*
+ * configure the FID, VD, HD pin polarity,
+ * fld,hd pol positive, vd negative, 8-bit data
+ */
+ syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE | CCDC_SYN_MODE_8BITS;
+ } else {
+ /* y/c external sync mode */
+ syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+ CCDC_FID_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) <<
+ CCDC_HD_POL_SHIFT) |
+ ((params->vd_pol & CCDC_VD_POL_MASK) <<
+ CCDC_VD_POL_SHIFT));
+ }
+ regw(syn_mode, CCDC_SYN_MODE);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+ /*
+ * configure the order of y cb cr in SDRAM, and disable latch
+ * internal register on vsync
+ */
+ regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+ CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+ /*
+ * configure the horizontal line offset. This should be a
+ * on 32 byte bondary. So clear LSB 5 bits
+ */
+ regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+ /* two fields are interleaved in memory */
+ regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
+
+ ccdc_sbl_reset();
+ dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
+ ccdc_readregs();
+}
+
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+ u32 val;
+
+ if (!bclamp->enable) {
+ /* configure DCSub */
+ val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
+ regw(val, CCDC_DCSUB);
+ dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val);
+ regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
+ dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n");
+ return;
+ }
+ /*
+ * Configure gain, Start pixel, No of line to be avg,
+ * No of pixel/line to be avg, & Enable the Black clamping
+ */
+ val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
+ ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
+ CCDC_BLK_ST_PXL_SHIFT) |
+ ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
+ CCDC_BLK_SAMPLE_LINE_SHIFT) |
+ ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+ CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
+ regw(val, CCDC_CLAMP);
+ dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val);
+ /* If Black clamping is enable then make dcsub 0 */
+ regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
+ dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n");
+}
+
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+ u32 val;
+
+ val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
+ ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GB_COMP_SHIFT) |
+ ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GR_COMP_SHIFT) |
+ ((bcomp->r & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_R_COMP_SHIFT));
+ regw(val, CCDC_BLKCMP);
+}
+
+static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
+{
+ u32 val;
+
+ /* Initially disable FPC */
+ val = CCDC_FPC_DISABLE;
+ regw(val, CCDC_FPC);
+
+ if (!fpc->enable)
+ return;
+
+ /* Configure Fault pixel if needed */
+ regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
+ dev_dbg(dev, "\nWriting 0x%x to FPC_ADDR...\n",
+ (fpc->fpc_table_addr));
+ /* Write the FPC params with FPC disable */
+ val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
+ regw(val, CCDC_FPC);
+
+ dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
+ /* read the FPC register */
+ val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
+ regw(val, CCDC_FPC);
+ dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
+}
+
+/*
+ * ccdc_config_raw()
+ * This function will configure CCDC for Raw capture mode
+ */
+void ccdc_config_raw(void)
+{
+ struct ccdc_params_raw *params = &ccdc_hw_params_raw;
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int syn_mode = 0;
+ unsigned int val;
+
+ dev_dbg(dev, "\nStarting ccdc_config_raw...");
+
+ /* Reset CCDC */
+ ccdc_restore_defaults();
+
+ /* Disable latching function registers on VSYNC */
+ regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+ /*
+ * Configure the vertical sync polarity(SYN_MODE.VDPOL),
+ * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
+ * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
+ * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
+ * SDRAM, enable internal timing generator
+ */
+ syn_mode =
+ (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+ ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+ ((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
+ CCDC_DATA_SZ_SHIFT) |
+ ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
+ CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
+
+ /* Enable and configure aLaw register if needed */
+ if (config_params->alaw.enable) {
+ val = ((config_params->alaw.gama_wd &
+ CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
+ regw(val, CCDC_ALAW);
+ dev_dbg(dev, "\nWriting 0x%x to ALAW...\n", val);
+ }
+
+ /* Configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW);
+
+ /* Configure Black Clamp */
+ ccdc_config_black_clamp(&config_params->blk_clamp);
+
+ /* Configure Black level compensation */
+ ccdc_config_black_compense(&config_params->blk_comp);
+
+ /* Configure Fault Pixel Correction */
+ ccdc_config_fpc(&config_params->fault_pxl);
+
+ /* If data size is 8 bit then pack the data */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ syn_mode |= CCDC_DATA_PACK_ENABLE;
+
+#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
+ /* enable video port */
+ val = CCDC_ENABLE_VIDEO_PORT;
+#else
+ /* disable video port */
+ val = CCDC_DISABLE_VIDEO_PORT;
+#endif
+
+ if (config_params->data_sz == CCDC_DATA_8BITS)
+ val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
+ << CCDC_FMTCFG_VPIN_SHIFT;
+ else
+ val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
+ << CCDC_FMTCFG_VPIN_SHIFT;
+ /* Write value in FMTCFG */
+ regw(val, CCDC_FMTCFG);
+
+ dev_dbg(dev, "\nWriting 0x%x to FMTCFG...\n", val);
+ /* Configure the color pattern according to mt9t001 sensor */
+ regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
+
+ dev_dbg(dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
+ /*
+ * Configure Data formatter(Video port) pixel selection
+ * (FMT_HORZ, FMT_VERT)
+ */
+ val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
+ CCDC_FMT_HORZ_FMTSPH_SHIFT) |
+ (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
+ regw(val, CCDC_FMT_HORZ);
+
+ dev_dbg(dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
+ val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
+ << CCDC_FMT_VERT_FMTSLV_SHIFT;
+ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
+ else
+ val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
+
+ dev_dbg(dev, "\nparams->win.height 0x%x ...\n",
+ params->win.height);
+ regw(val, CCDC_FMT_VERT);
+
+ dev_dbg(dev, "\nWriting 0x%x to FMT_VERT...\n", val);
+
+ dev_dbg(dev, "\nbelow regw(val, FMT_VERT)...");
+
+ /*
+ * Configure Horizontal offset register. If pack 8 is enabled then
+ * 1 pixel will take 1 byte
+ */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
+ CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
+ else
+ /* else one pixel will take 2 byte */
+ regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
+ CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
+ CCDC_HSIZE_OFF);
+
+ /* Set value for SDOFST */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_enable) {
+ /* For intelace inverse mode */
+ regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n");
+ }
+
+ else {
+ /* For intelace non inverse mode */
+ regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(dev, "\nWriting 0x0249 to SDOFST...\n");
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n");
+ }
+
+ /*
+ * Configure video port pixel selection (VPOUT)
+ * Here -1 is to make the height value less than FMT_VERT.FMTLNV
+ */
+ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
+ << CCDC_VP_OUT_VERT_NUM_SHIFT;
+ else
+ val =
+ ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
+ 1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
+ CCDC_VP_OUT_VERT_NUM_SHIFT;
+
+ val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
+ << CCDC_VP_OUT_HORZ_NUM_SHIFT;
+ val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
+ regw(val, CCDC_VP_OUT);
+
+ dev_dbg(dev, "\nWriting 0x%x to VP_OUT...\n", val);
+ regw(syn_mode, CCDC_SYN_MODE);
+ dev_dbg(dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
+
+ ccdc_sbl_reset();
+ dev_dbg(dev, "\nend of ccdc_config_raw...");
+ ccdc_readregs();
+}
+
+static int ccdc_configure(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_config_raw();
+ else
+ ccdc_config_ycbcr();
+ return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.buf_type = buf_type;
+ else
+ ccdc_hw_params_ycbcr.buf_type = buf_type;
+ return 0;
+}
+
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.buf_type;
+ return ccdc_hw_params_ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+ *pix = ccdc_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+ *pix = ccdc_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+ ccdc_hw_params_raw.config_params.alaw.enable = 1;
+ else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+ return -EINVAL;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static u32 ccdc_get_pixel_format(void)
+{
+ struct ccdc_a_law *alaw =
+ &ccdc_hw_params_raw.config_params.alaw;
+ u32 pixfmt;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (alaw->enable)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.win = *win;
+ else
+ ccdc_hw_params_ycbcr.win = *win;
+ return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ *win = ccdc_hw_params_raw.win;
+ else
+ *win = ccdc_hw_params_ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int len;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if ((config_params->alaw.enable) ||
+ (config_params->data_sz == CCDC_DATA_8BITS))
+ len = ccdc_hw_params_raw.win.width;
+ else
+ len = ccdc_hw_params_raw.win.width * 2;
+ } else
+ len = ccdc_hw_params_ycbcr.win.width * 2;
+ return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.frm_fmt = frm_fmt;
+ else
+ ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.frm_fmt;
+ else
+ return ccdc_hw_params_ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+ return (regr(CCDC_SYN_MODE) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+ regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ ccdc_if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_YCBCR_SYNC_16:
+ case VPFE_YCBCR_SYNC_8:
+ ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
+ ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
+ break;
+ default:
+ /* TODO add support for raw bayer here */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct ccdc_hw_device ccdc_hw_dev = {
+ .name = "DM6446 CCDC",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = ccdc_open,
+ .close = ccdc_close,
+ .set_ccdc_base = ccdc_set_ccdc_base,
+ .reset = ccdc_sbl_reset,
+ .enable = ccdc_enable,
+ .set_hw_if_params = ccdc_set_hw_if_params,
+ .set_params = ccdc_set_params,
+ .configure = ccdc_configure,
+ .set_buftype = ccdc_set_buftype,
+ .get_buftype = ccdc_get_buftype,
+ .enum_pix = ccdc_enum_pix,
+ .set_pixel_format = ccdc_set_pixel_format,
+ .get_pixel_format = ccdc_get_pixel_format,
+ .set_frame_format = ccdc_set_frame_format,
+ .get_frame_format = ccdc_get_frame_format,
+ .set_image_window = ccdc_set_image_window,
+ .get_image_window = ccdc_get_image_window,
+ .get_line_length = ccdc_get_line_length,
+ .setfbaddr = ccdc_setfbaddr,
+ .getfid = ccdc_getfid,
+ },
+};
+
+static int dm644x_ccdc_init(void)
+{
+ printk(KERN_NOTICE "dm644x_ccdc_init\n");
+ if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
+ return -1;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n",
+ ccdc_hw_dev.name);
+ return 0;
+}
+
+static void dm644x_ccdc_exit(void)
+{
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+}
+
+module_init(dm644x_ccdc_init);
+module_exit(dm644x_ccdc_exit);
diff --git a/drivers/media/video/davinci/dm644x_ccdc_regs.h b/drivers/media/video/davinci/dm644x_ccdc_regs.h
new file mode 100644
index 000000000000..6e5d05324466
--- /dev/null
+++ b/drivers/media/video/davinci/dm644x_ccdc_regs.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * 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
+ */
+#ifndef _DM644X_CCDC_REGS_H
+#define _DM644X_CCDC_REGS_H
+
+/**************************************************************************\
+* Register OFFSET Definitions
+\**************************************************************************/
+#define CCDC_PID 0x0
+#define CCDC_PCR 0x4
+#define CCDC_SYN_MODE 0x8
+#define CCDC_HD_VD_WID 0xc
+#define CCDC_PIX_LINES 0x10
+#define CCDC_HORZ_INFO 0x14
+#define CCDC_VERT_START 0x18
+#define CCDC_VERT_LINES 0x1c
+#define CCDC_CULLING 0x20
+#define CCDC_HSIZE_OFF 0x24
+#define CCDC_SDOFST 0x28
+#define CCDC_SDR_ADDR 0x2c
+#define CCDC_CLAMP 0x30
+#define CCDC_DCSUB 0x34
+#define CCDC_COLPTN 0x38
+#define CCDC_BLKCMP 0x3c
+#define CCDC_FPC 0x40
+#define CCDC_FPC_ADDR 0x44
+#define CCDC_VDINT 0x48
+#define CCDC_ALAW 0x4c
+#define CCDC_REC656IF 0x50
+#define CCDC_CCDCFG 0x54
+#define CCDC_FMTCFG 0x58
+#define CCDC_FMT_HORZ 0x5c
+#define CCDC_FMT_VERT 0x60
+#define CCDC_FMT_ADDR0 0x64
+#define CCDC_FMT_ADDR1 0x68
+#define CCDC_FMT_ADDR2 0x6c
+#define CCDC_FMT_ADDR3 0x70
+#define CCDC_FMT_ADDR4 0x74
+#define CCDC_FMT_ADDR5 0x78
+#define CCDC_FMT_ADDR6 0x7c
+#define CCDC_FMT_ADDR7 0x80
+#define CCDC_PRGEVEN_0 0x84
+#define CCDC_PRGEVEN_1 0x88
+#define CCDC_PRGODD_0 0x8c
+#define CCDC_PRGODD_1 0x90
+#define CCDC_VP_OUT 0x94
+
+
+/***************************************************************
+* Define for various register bit mask and shifts for CCDC
+****************************************************************/
+#define CCDC_FID_POL_MASK 1
+#define CCDC_FID_POL_SHIFT 4
+#define CCDC_HD_POL_MASK 1
+#define CCDC_HD_POL_SHIFT 3
+#define CCDC_VD_POL_MASK 1
+#define CCDC_VD_POL_SHIFT 2
+#define CCDC_HSIZE_OFF_MASK 0xffffffe0
+#define CCDC_32BYTE_ALIGN_VAL 31
+#define CCDC_FRM_FMT_MASK 0x1
+#define CCDC_FRM_FMT_SHIFT 7
+#define CCDC_DATA_SZ_MASK 7
+#define CCDC_DATA_SZ_SHIFT 8
+#define CCDC_PIX_FMT_MASK 3
+#define CCDC_PIX_FMT_SHIFT 12
+#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF
+#define CCDC_WEN_ENABLE (1 << 17)
+#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF
+#define CCDC_VDHDEN_ENABLE (1 << 16)
+#define CCDC_LPF_ENABLE (1 << 14)
+#define CCDC_ALAW_ENABLE (1 << 3)
+#define CCDC_ALAW_GAMA_WD_MASK 7
+#define CCDC_BLK_CLAMP_ENABLE (1 << 31)
+#define CCDC_BLK_SGAIN_MASK 0x1F
+#define CCDC_BLK_ST_PXL_MASK 0x7FFF
+#define CCDC_BLK_ST_PXL_SHIFT 10
+#define CCDC_BLK_SAMPLE_LN_MASK 7
+#define CCDC_BLK_SAMPLE_LN_SHIFT 28
+#define CCDC_BLK_SAMPLE_LINE_MASK 7
+#define CCDC_BLK_SAMPLE_LINE_SHIFT 25
+#define CCDC_BLK_DC_SUB_MASK 0x03FFF
+#define CCDC_BLK_COMP_MASK 0xFF
+#define CCDC_BLK_COMP_GB_COMP_SHIFT 8
+#define CCDC_BLK_COMP_GR_COMP_SHIFT 16
+#define CCDC_BLK_COMP_R_COMP_SHIFT 24
+#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15)
+#define CCDC_FPC_ENABLE (1 << 15)
+#define CCDC_FPC_DISABLE 0
+#define CCDC_FPC_FPC_NUM_MASK 0x7FFF
+#define CCDC_DATA_PACK_ENABLE (1 << 11)
+#define CCDC_FMTCFG_VPIN_MASK 7
+#define CCDC_FMTCFG_VPIN_SHIFT 12
+#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16
+#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_SHIFT 16
+#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF
+#define CCDC_VP_OUT_VERT_NUM_SHIFT 17
+#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF
+#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4
+#define CCDC_VP_OUT_HORZ_ST_MASK 0xF
+#define CCDC_HORZ_INFO_SPH_SHIFT 16
+#define CCDC_VERT_START_SLV0_SHIFT 16
+#define CCDC_VDINT_VDINT0_SHIFT 16
+#define CCDC_VDINT_VDINT1_MASK 0xFFFF
+#define CCDC_PPC_RAW 1
+#define CCDC_DCSUB_DEFAULT_VAL 0
+#define CCDC_CLAMP_DEFAULT_VAL 0
+#define CCDC_ENABLE_VIDEO_PORT 0x8000
+#define CCDC_DISABLE_VIDEO_PORT 0
+#define CCDC_COLPTN_VAL 0xBB11BB11
+#define CCDC_TWO_BYTES_PER_PIXEL 2
+#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D
+#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249
+#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000
+#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0
+#define CCDC_INTERLACED_HEIGHT_SHIFT 1
+#define CCDC_SYN_MODE_INPMOD_SHIFT 12
+#define CCDC_SYN_MODE_INPMOD_MASK 3
+#define CCDC_SYN_MODE_8BITS (7 << 8)
+#define CCDC_SYN_FLDMODE_MASK 1
+#define CCDC_SYN_FLDMODE_SHIFT 7
+#define CCDC_REC656IF_BT656_EN 3
+#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2)
+#define CCDC_CCDCFG_Y8POS_SHIFT 11
+#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249
+#define CCDC_NO_CULLING 0xffff00ff
+#endif
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
new file mode 100644
index 000000000000..402ce43ef38e
--- /dev/null
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -0,0 +1,2124 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * Driver name : VPFE Capture driver
+ * VPFE Capture driver allows applications to capture and stream video
+ * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
+ * TVP5146 or Raw Bayer RGB image data from an image sensor
+ * such as Microns' MT9T001, MT9T031 etc.
+ *
+ * These SoCs have, in common, a Video Processing Subsystem (VPSS) that
+ * consists of a Video Processing Front End (VPFE) for capturing
+ * video/raw image data and Video Processing Back End (VPBE) for displaying
+ * YUV data through an in-built analog encoder or Digital LCD port. This
+ * driver is for capture through VPFE. A typical EVM using these SoCs have
+ * following high level configuration.
+ *
+ *
+ * decoder(TVP5146/ YUV/
+ * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF)
+ * data input | |
+ * V |
+ * SDRAM |
+ * V
+ * Image Processor
+ * |
+ * V
+ * SDRAM
+ * The data flow happens from a decoder connected to the VPFE over a
+ * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface
+ * and to the input of VPFE through an optional MUX (if more inputs are
+ * to be interfaced on the EVM). The input data is first passed through
+ * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC
+ * does very little or no processing on YUV data and does pre-process Raw
+ * Bayer RGB data through modules such as Defect Pixel Correction (DFC)
+ * Color Space Conversion (CSC), data gain/offset etc. After this, data
+ * can be written to SDRAM or can be connected to the image processing
+ * block such as IPIPE (on DM355 only).
+ *
+ * Features supported
+ * - MMAP IO
+ * - Capture using TVP5146 over BT.656
+ * - support for interfacing decoders using sub device model
+ * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV
+ * data capture to SDRAM.
+ * TODO list
+ * - Support multiple REQBUF after open
+ * - Support for de-allocating buffers through REQBUF
+ * - Support for Raw Bayer RGB capture
+ * - Support for chaining Image Processor
+ * - Support for static allocation of buffers
+ * - Support for USERPTR IO
+ * - Support for STREAMON before QBUF
+ * - Support for control ioctls
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <linux/io.h>
+#include <media/davinci/vpfe_capture.h>
+#include "ccdc_hw_device.h"
+
+static int debug;
+static u32 numbuffers = 3;
+static u32 bufsize = (720 * 576 * 2);
+
+module_param(numbuffers, uint, S_IRUGO);
+module_param(bufsize, uint, S_IRUGO);
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(numbuffers, "buffer count (default:3)");
+MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/* standard information */
+struct vpfe_standard {
+ v4l2_std_id std_id;
+ unsigned int width;
+ unsigned int height;
+ struct v4l2_fract pixelaspect;
+ /* 0 - progressive, 1 - interlaced */
+ int frame_format;
+};
+
+/* ccdc configuration */
+struct ccdc_config {
+ /* This make sure vpfe is probed and ready to go */
+ int vpfe_probed;
+ /* name of ccdc device */
+ char name[32];
+ /* for storing mem maps for CCDC */
+ int ccdc_addr_size;
+ void *__iomem ccdc_addr;
+};
+
+/* data structures */
+static struct vpfe_config_params config_params = {
+ .min_numbuffers = 3,
+ .numbuffers = 3,
+ .min_bufsize = 720 * 480 * 2,
+ .device_bufsize = 720 * 576 * 2,
+};
+
+/* ccdc device registered */
+static struct ccdc_hw_device *ccdc_dev;
+/* lock for accessing ccdc information */
+static DEFINE_MUTEX(ccdc_lock);
+/* ccdc configuration */
+static struct ccdc_config *ccdc_cfg;
+
+const struct vpfe_standard vpfe_standards[] = {
+ {V4L2_STD_525_60, 720, 480, {11, 10}, 1},
+ {V4L2_STD_625_50, 720, 576, {54, 59}, 1},
+};
+
+/* Used when raw Bayer image from ccdc is directly captured to SDRAM */
+static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
+ {
+ .fmtdesc = {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb 8bit A-Law compr.",
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ },
+ .bpp = 1,
+ },
+ {
+ .fmtdesc = {
+ .index = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb - 16bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR16,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb 8bit DPCM compr.",
+ .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
+ },
+ .bpp = 1,
+ },
+ {
+ .fmtdesc = {
+ .index = 3,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "YCbCr 4:2:2 Interleaved UYVY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 4,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "YCbCr 4:2:2 Interleaved YUYV",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 5,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Y/CbCr 4:2:0 - Semi planar",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ },
+ .bpp = 1,
+ },
+};
+
+/*
+ * vpfe_lookup_pix_format()
+ * lookup an entry in the vpfe pix format table based on pix_format
+ */
+static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) {
+ if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat)
+ return &vpfe_pix_fmts[i];
+ }
+ return NULL;
+}
+
+/*
+ * vpfe_register_ccdc_device. CCDC module calls this to
+ * register with vpfe capture
+ */
+int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
+{
+ int ret = 0;
+ printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name);
+
+ BUG_ON(!dev->hw_ops.open);
+ BUG_ON(!dev->hw_ops.enable);
+ BUG_ON(!dev->hw_ops.set_hw_if_params);
+ BUG_ON(!dev->hw_ops.configure);
+ BUG_ON(!dev->hw_ops.set_buftype);
+ BUG_ON(!dev->hw_ops.get_buftype);
+ BUG_ON(!dev->hw_ops.enum_pix);
+ BUG_ON(!dev->hw_ops.set_frame_format);
+ BUG_ON(!dev->hw_ops.get_frame_format);
+ BUG_ON(!dev->hw_ops.get_pixel_format);
+ BUG_ON(!dev->hw_ops.set_pixel_format);
+ BUG_ON(!dev->hw_ops.set_params);
+ BUG_ON(!dev->hw_ops.set_image_window);
+ BUG_ON(!dev->hw_ops.get_image_window);
+ BUG_ON(!dev->hw_ops.get_line_length);
+ BUG_ON(!dev->hw_ops.setfbaddr);
+ BUG_ON(!dev->hw_ops.getfid);
+
+ mutex_lock(&ccdc_lock);
+ if (NULL == ccdc_cfg) {
+ /*
+ * TODO. Will this ever happen? if so, we need to fix it.
+ * Proabably we need to add the request to a linked list and
+ * walk through it during vpfe probe
+ */
+ printk(KERN_ERR "vpfe capture not initialized\n");
+ ret = -1;
+ goto unlock;
+ }
+
+ if (strcmp(dev->name, ccdc_cfg->name)) {
+ /* ignore this ccdc */
+ ret = -1;
+ goto unlock;
+ }
+
+ if (ccdc_dev) {
+ printk(KERN_ERR "ccdc already registered\n");
+ ret = -1;
+ goto unlock;
+ }
+
+ ccdc_dev = dev;
+ dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr,
+ ccdc_cfg->ccdc_addr_size);
+unlock:
+ mutex_unlock(&ccdc_lock);
+ return ret;
+}
+EXPORT_SYMBOL(vpfe_register_ccdc_device);
+
+/*
+ * vpfe_unregister_ccdc_device. CCDC module calls this to
+ * unregister with vpfe capture
+ */
+void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev)
+{
+ if (NULL == dev) {
+ printk(KERN_ERR "invalid ccdc device ptr\n");
+ return;
+ }
+
+ printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n",
+ dev->name);
+
+ if (strcmp(dev->name, ccdc_cfg->name)) {
+ /* ignore this ccdc */
+ return;
+ }
+
+ mutex_lock(&ccdc_lock);
+ ccdc_dev = NULL;
+ mutex_unlock(&ccdc_lock);
+ return;
+}
+EXPORT_SYMBOL(vpfe_unregister_ccdc_device);
+
+/*
+ * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
+ */
+static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
+ struct v4l2_format *f)
+{
+ struct v4l2_rect image_win;
+ enum ccdc_buftype buf_type;
+ enum ccdc_frmfmt frm_fmt;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ ccdc_dev->hw_ops.get_image_window(&image_win);
+ f->fmt.pix.width = image_win.width;
+ f->fmt.pix.height = image_win.height;
+ f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length();
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+ f->fmt.pix.height;
+ buf_type = ccdc_dev->hw_ops.get_buftype();
+ f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format();
+ frm_fmt = ccdc_dev->hw_ops.get_frame_format();
+ if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ else if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED)
+ f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+ else {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n");
+ return -EINVAL;
+ }
+ } else {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * vpfe_config_ccdc_image_format()
+ * For a pix format, configure ccdc to setup the capture
+ */
+static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+ int ret = 0;
+
+ if (ccdc_dev->hw_ops.set_pixel_format(
+ vpfe_dev->fmt.fmt.pix.pixelformat) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "couldn't set pix format in ccdc\n");
+ return -EINVAL;
+ }
+ /* configure the image window */
+ ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop);
+
+ switch (vpfe_dev->fmt.fmt.pix.field) {
+ case V4L2_FIELD_INTERLACED:
+ /* do nothing, since it is default */
+ ret = ccdc_dev->hw_ops.set_buftype(
+ CCDC_BUFTYPE_FLD_INTERLEAVED);
+ break;
+ case V4L2_FIELD_NONE:
+ frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
+ /* buffer type only applicable for interlaced scan */
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ ret = ccdc_dev->hw_ops.set_buftype(
+ CCDC_BUFTYPE_FLD_SEPARATED);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set the frame format */
+ if (!ret)
+ ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt);
+ return ret;
+}
+/*
+ * vpfe_config_image_format()
+ * For a given standard, this functions sets up the default
+ * pix format & crop values in the vpfe device and ccdc. It first
+ * starts with defaults based values from the standard table.
+ * It then checks if sub device support g_fmt and then override the
+ * values based on that.Sets crop values to match with scan resolution
+ * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
+ * values in ccdc
+ */
+static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
+ const v4l2_std_id *std_id)
+{
+ struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+ int i, ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
+ if (vpfe_standards[i].std_id & *std_id) {
+ vpfe_dev->std_info.active_pixels =
+ vpfe_standards[i].width;
+ vpfe_dev->std_info.active_lines =
+ vpfe_standards[i].height;
+ vpfe_dev->std_info.frame_format =
+ vpfe_standards[i].frame_format;
+ vpfe_dev->std_index = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(vpfe_standards)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n");
+ return -EINVAL;
+ }
+
+ vpfe_dev->crop.top = 0;
+ vpfe_dev->crop.left = 0;
+ vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels;
+ vpfe_dev->crop.height = vpfe_dev->std_info.active_lines;
+ vpfe_dev->fmt.fmt.pix.width = vpfe_dev->crop.width;
+ vpfe_dev->fmt.fmt.pix.height = vpfe_dev->crop.height;
+
+ /* first field and frame format based on standard frame format */
+ if (vpfe_dev->std_info.frame_format) {
+ vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+ /* assume V4L2_PIX_FMT_UYVY as default */
+ vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ } else {
+ vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ /* assume V4L2_PIX_FMT_SBGGR8 */
+ vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ }
+
+ /* if sub device supports g_fmt, override the defaults */
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+ sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt);
+
+ if (ret && ret != -ENOIOCTLCMD) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "error in getting g_fmt from sub device\n");
+ return ret;
+ }
+
+ /* Sets the values in CCDC */
+ ret = vpfe_config_ccdc_image_format(vpfe_dev);
+ if (ret)
+ return ret;
+
+ /* Update the values of sizeimage and bytesperline */
+ if (!ret) {
+ vpfe_dev->fmt.fmt.pix.bytesperline =
+ ccdc_dev->hw_ops.get_line_length();
+ vpfe_dev->fmt.fmt.pix.sizeimage =
+ vpfe_dev->fmt.fmt.pix.bytesperline *
+ vpfe_dev->fmt.fmt.pix.height;
+ }
+ return ret;
+}
+
+static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
+{
+ int ret = 0;
+
+ /* set first input of current subdevice as the current input */
+ vpfe_dev->current_input = 0;
+
+ /* set default standard */
+ vpfe_dev->std_index = 0;
+
+ /* Configure the default format information */
+ ret = vpfe_config_image_format(vpfe_dev,
+ &vpfe_standards[vpfe_dev->std_index].std_id);
+ if (ret)
+ return ret;
+
+ /* now open the ccdc device to initialize it */
+ mutex_lock(&ccdc_lock);
+ if (NULL == ccdc_dev) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n");
+ ret = -ENODEV;
+ goto unlock;
+ }
+
+ if (!try_module_get(ccdc_dev->owner)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n");
+ ret = -ENODEV;
+ goto unlock;
+ }
+ ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev);
+ if (!ret)
+ vpfe_dev->initialized = 1;
+unlock:
+ mutex_unlock(&ccdc_lock);
+ return ret;
+}
+
+/*
+ * vpfe_open : It creates object of file handle structure and
+ * stores it in private_data member of filepointer
+ */
+static int vpfe_open(struct file *file)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n");
+
+ if (!vpfe_dev->cfg->num_subdevs) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n");
+ return -ENODEV;
+ }
+
+ /* Allocate memory for the file handle object */
+ fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
+ if (NULL == fh) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+ /* store pointer to fh in private_data member of file */
+ file->private_data = fh;
+ fh->vpfe_dev = vpfe_dev;
+ mutex_lock(&vpfe_dev->lock);
+ /* If decoder is not initialized. initialize it */
+ if (!vpfe_dev->initialized) {
+ if (vpfe_initialize_device(vpfe_dev)) {
+ mutex_unlock(&vpfe_dev->lock);
+ return -ENODEV;
+ }
+ }
+ /* Increment device usrs counter */
+ vpfe_dev->usrs++;
+ /* Set io_allowed member to false */
+ fh->io_allowed = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&vpfe_dev->prio, &fh->prio);
+ mutex_unlock(&vpfe_dev->lock);
+ return 0;
+}
+
+static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev)
+{
+ unsigned long addr;
+
+ vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+ struct videobuf_buffer, queue);
+ list_del(&vpfe_dev->next_frm->queue);
+ vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE;
+ addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
+ ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev)
+{
+ struct timeval timevalue;
+
+ do_gettimeofday(&timevalue);
+ vpfe_dev->cur_frm->ts = timevalue;
+ vpfe_dev->cur_frm->state = VIDEOBUF_DONE;
+ vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+ wake_up_interruptible(&vpfe_dev->cur_frm->done);
+ vpfe_dev->cur_frm = vpfe_dev->next_frm;
+}
+
+/* ISR for VINT0*/
+static irqreturn_t vpfe_isr(int irq, void *dev_id)
+{
+ struct vpfe_device *vpfe_dev = dev_id;
+ enum v4l2_field field;
+ unsigned long addr;
+ int fid;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n");
+ field = vpfe_dev->fmt.fmt.pix.field;
+
+ /* if streaming not started, don't do anything */
+ if (!vpfe_dev->started)
+ return IRQ_HANDLED;
+
+ /* only for 6446 this will be applicable */
+ if (NULL != ccdc_dev->hw_ops.reset)
+ ccdc_dev->hw_ops.reset();
+
+ if (field == V4L2_FIELD_NONE) {
+ /* handle progressive frame capture */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "frame format is progressive...\n");
+ if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+ vpfe_process_buffer_complete(vpfe_dev);
+ return IRQ_HANDLED;
+ }
+
+ /* interlaced or TB capture check which field we are in hardware */
+ fid = ccdc_dev->hw_ops.getfid();
+
+ /* switch the software maintained field id */
+ vpfe_dev->field_id ^= 1;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n",
+ fid, vpfe_dev->field_id);
+ if (fid == vpfe_dev->field_id) {
+ /* we are in-sync here,continue */
+ if (fid == 0) {
+ /*
+ * One frame is just being captured. If the next frame
+ * is available, release the current frame and move on
+ */
+ if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+ vpfe_process_buffer_complete(vpfe_dev);
+ /*
+ * based on whether the two fields are stored
+ * interleavely or separately in memory, reconfigure
+ * the CCDC memory address
+ */
+ if (field == V4L2_FIELD_SEQ_TB) {
+ addr =
+ videobuf_to_dma_contig(vpfe_dev->cur_frm);
+ addr += vpfe_dev->field_off;
+ ccdc_dev->hw_ops.setfbaddr(addr);
+ }
+ return IRQ_HANDLED;
+ }
+ /*
+ * if one field is just being captured configure
+ * the next frame get the next frame from the empty
+ * queue if no frame is available hold on to the
+ * current buffer
+ */
+ spin_lock(&vpfe_dev->dma_queue_lock);
+ if (!list_empty(&vpfe_dev->dma_queue) &&
+ vpfe_dev->cur_frm == vpfe_dev->next_frm)
+ vpfe_schedule_next_buffer(vpfe_dev);
+ spin_unlock(&vpfe_dev->dma_queue_lock);
+ } else if (fid == 0) {
+ /*
+ * out of sync. Recover from any hardware out-of-sync.
+ * May loose one frame
+ */
+ vpfe_dev->field_id = fid;
+ }
+ return IRQ_HANDLED;
+}
+
+/* vdint1_isr - isr handler for VINT1 interrupt */
+static irqreturn_t vdint1_isr(int irq, void *dev_id)
+{
+ struct vpfe_device *vpfe_dev = dev_id;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n");
+
+ /* if streaming not started, don't do anything */
+ if (!vpfe_dev->started)
+ return IRQ_HANDLED;
+
+ spin_lock(&vpfe_dev->dma_queue_lock);
+ if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) &&
+ !list_empty(&vpfe_dev->dma_queue) &&
+ vpfe_dev->cur_frm == vpfe_dev->next_frm)
+ vpfe_schedule_next_buffer(vpfe_dev);
+ spin_unlock(&vpfe_dev->dma_queue_lock);
+ return IRQ_HANDLED;
+}
+
+static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = ccdc_dev->hw_ops.get_frame_format();
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
+ free_irq(IRQ_VDINT1, vpfe_dev);
+}
+
+static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = ccdc_dev->hw_ops.get_frame_format();
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE) {
+ return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr,
+ IRQF_DISABLED, "vpfe_capture1",
+ vpfe_dev);
+ }
+ return 0;
+}
+
+/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */
+static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+ vpfe_dev->started = 0;
+ ccdc_dev->hw_ops.enable(0);
+ if (ccdc_dev->hw_ops.enable_out_to_sdram)
+ ccdc_dev->hw_ops.enable_out_to_sdram(0);
+}
+
+/*
+ * vpfe_release : This function deletes buffer queue, frees the
+ * buffers and the vpfe file handle
+ */
+static int vpfe_release(struct file *file)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
+
+ /* Get the device lock */
+ mutex_lock(&vpfe_dev->lock);
+ /* if this instance is doing IO */
+ if (fh->io_allowed) {
+ if (vpfe_dev->started) {
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+ sdinfo->grp_id,
+ video, s_stream, 0);
+ if (ret && (ret != -ENOIOCTLCMD))
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "stream off failed in subdev\n");
+ vpfe_stop_ccdc_capture(vpfe_dev);
+ vpfe_detach_irq(vpfe_dev);
+ videobuf_streamoff(&vpfe_dev->buffer_queue);
+ }
+ vpfe_dev->io_usrs = 0;
+ vpfe_dev->numbuffers = config_params.numbuffers;
+ }
+
+ /* Decrement device usrs counter */
+ vpfe_dev->usrs--;
+ /* Close the priority */
+ v4l2_prio_close(&vpfe_dev->prio, &fh->prio);
+ /* If this is the last file handle */
+ if (!vpfe_dev->usrs) {
+ vpfe_dev->initialized = 0;
+ if (ccdc_dev->hw_ops.close)
+ ccdc_dev->hw_ops.close(vpfe_dev->pdev);
+ module_put(ccdc_dev->owner);
+ }
+ mutex_unlock(&vpfe_dev->lock);
+ file->private_data = NULL;
+ /* Free memory allocated to file handle object */
+ kfree(fh);
+ return 0;
+}
+
+/*
+ * vpfe_mmap : It is used to map kernel space buffers
+ * into user spaces
+ */
+static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ /* Get the device object and file handle object */
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
+
+ return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma);
+}
+
+/*
+ * vpfe_poll: It is used for select/poll system call
+ */
+static unsigned int vpfe_poll(struct file *file, poll_table *wait)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
+
+ if (vpfe_dev->started)
+ return videobuf_poll_stream(file,
+ &vpfe_dev->buffer_queue, wait);
+ return 0;
+}
+
+/* vpfe capture driver file operations */
+static const struct v4l2_file_operations vpfe_fops = {
+ .owner = THIS_MODULE,
+ .open = vpfe_open,
+ .release = vpfe_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vpfe_mmap,
+ .poll = vpfe_poll
+};
+
+/*
+ * vpfe_check_format()
+ * This function adjust the input pixel format as per hardware
+ * capabilities and update the same in pixfmt.
+ * Following algorithm used :-
+ *
+ * If given pixformat is not in the vpfe list of pix formats or not
+ * supported by the hardware, current value of pixformat in the device
+ * is used
+ * If given field is not supported, then current field is used. If field
+ * is different from current, then it is matched with that from sub device.
+ * Minimum height is 2 lines for interlaced or tb field and 1 line for
+ * progressive. Maximum height is clamped to active active lines of scan
+ * Minimum width is 32 bytes in memory and width is clamped to active
+ * pixels of scan.
+ * bytesperline is a multiple of 32.
+ */
+static const struct vpfe_pixel_format *
+ vpfe_check_format(struct vpfe_device *vpfe_dev,
+ struct v4l2_pix_format *pixfmt)
+{
+ u32 min_height = 1, min_width = 32, max_width, max_height;
+ const struct vpfe_pixel_format *vpfe_pix_fmt;
+ u32 pix;
+ int temp, found;
+
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ if (NULL == vpfe_pix_fmt) {
+ /*
+ * use current pixel format in the vpfe device. We
+ * will find this pix format in the table
+ */
+ pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ }
+
+ /* check if hw supports it */
+ temp = 0;
+ found = 0;
+ while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) {
+ if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) {
+ found = 1;
+ break;
+ }
+ temp++;
+ }
+
+ if (!found) {
+ /* use current pixel format */
+ pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+ /*
+ * Since this is currently used in the vpfe device, we
+ * will find this pix format in the table
+ */
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ }
+
+ /* check what field format is supported */
+ if (pixfmt->field == V4L2_FIELD_ANY) {
+ /* if field is any, use current value as default */
+ pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+ }
+
+ /*
+ * if field is not same as current field in the vpfe device
+ * try matching the field with the sub device field
+ */
+ if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) {
+ /*
+ * If field value is not in the supported fields, use current
+ * field used in the device as default
+ */
+ switch (pixfmt->field) {
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_TB:
+ /* if sub device is supporting progressive, use that */
+ if (!vpfe_dev->std_info.frame_format)
+ pixfmt->field = V4L2_FIELD_NONE;
+ break;
+ case V4L2_FIELD_NONE:
+ if (vpfe_dev->std_info.frame_format)
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ break;
+
+ default:
+ /* use current field as default */
+ pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+ break;
+ }
+ }
+
+ /* Now adjust image resolutions supported */
+ if (pixfmt->field == V4L2_FIELD_INTERLACED ||
+ pixfmt->field == V4L2_FIELD_SEQ_TB)
+ min_height = 2;
+
+ max_width = vpfe_dev->std_info.active_pixels;
+ max_height = vpfe_dev->std_info.active_lines;
+ min_width /= vpfe_pix_fmt->bpp;
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n",
+ pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp);
+
+ pixfmt->width = clamp((pixfmt->width), min_width, max_width);
+ pixfmt->height = clamp((pixfmt->height), min_height, max_height);
+
+ /* If interlaced, adjust height to be a multiple of 2 */
+ if (pixfmt->field == V4L2_FIELD_INTERLACED)
+ pixfmt->height &= (~1);
+ /*
+ * recalculate bytesperline and sizeimage since width
+ * and height might have changed
+ */
+ pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31)
+ & ~31);
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+ pixfmt->sizeimage =
+ pixfmt->bytesperline * pixfmt->height +
+ ((pixfmt->bytesperline * pixfmt->height) >> 1);
+ else
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height ="
+ " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n",
+ pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp,
+ pixfmt->bytesperline, pixfmt->sizeimage);
+ return vpfe_pix_fmt;
+}
+
+static int vpfe_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
+
+ cap->version = VPFE_CAPTURE_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
+ strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
+ return 0;
+}
+
+static int vpfe_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
+ /* Fill in the information about format */
+ *fmt = vpfe_dev->fmt;
+ return ret;
+}
+
+static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmt;
+ int temp_index;
+ u32 pix;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n");
+
+ if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0)
+ return -EINVAL;
+
+ /* Fill in the information about format */
+ pix_fmt = vpfe_lookup_pix_format(pix);
+ if (NULL != pix_fmt) {
+ temp_index = fmt->index;
+ *fmt = pix_fmt->fmtdesc;
+ fmt->index = temp_index;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmts;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n");
+
+ /* If streaming is started, return error */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
+ return -EBUSY;
+ }
+
+ /* Check for valid frame format */
+ pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix);
+
+ if (NULL == pix_fmts)
+ return -EINVAL;
+
+ /* store the pixel format in the device object */
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ /* First detach any IRQ if currently attached */
+ vpfe_detach_irq(vpfe_dev);
+ vpfe_dev->fmt = *fmt;
+ /* set image capture parameters in the ccdc */
+ ret = vpfe_config_ccdc_image_format(vpfe_dev);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmts;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n");
+
+ pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix);
+ if (NULL == pix_fmts)
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a
+ * given app input index
+ */
+static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev,
+ int *subdev_index,
+ int *subdev_input_index,
+ int app_input_index)
+{
+ struct vpfe_config *cfg = vpfe_dev->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < cfg->num_subdevs; i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (app_input_index < (j + sdinfo->num_inputs)) {
+ *subdev_index = i;
+ *subdev_input_index = app_input_index - j;
+ return 0;
+ }
+ j += sdinfo->num_inputs;
+ }
+ return -EINVAL;
+}
+
+/*
+ * vpfe_get_app_input - Get app input index for a given subdev input index
+ * driver stores the input index of the current sub device and translate it
+ * when application request the current input
+ */
+static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev,
+ int *app_input_index)
+{
+ struct vpfe_config *cfg = vpfe_dev->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < cfg->num_subdevs; i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) {
+ if (vpfe_dev->current_input >= sdinfo->num_inputs)
+ return -1;
+ *app_input_index = j + vpfe_dev->current_input;
+ return 0;
+ }
+ j += sdinfo->num_inputs;
+ }
+ return -EINVAL;
+}
+
+static int vpfe_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int subdev, index ;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
+
+ if (vpfe_get_subdev_input_index(vpfe_dev,
+ &subdev,
+ &index,
+ inp->index) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "input information not found"
+ " for the subdev\n");
+ return -EINVAL;
+ }
+ sdinfo = &vpfe_dev->cfg->sub_devs[subdev];
+ memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input));
+ return 0;
+}
+
+static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
+
+ return vpfe_get_app_input_index(vpfe_dev, index);
+}
+
+
+static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int subdev_index, inp_index;
+ struct vpfe_route *route;
+ u32 input = 0, output = 0;
+ int ret = -EINVAL;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ /*
+ * If streaming is started return device busy
+ * error
+ */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ if (vpfe_get_subdev_input_index(vpfe_dev,
+ &subdev_index,
+ &inp_index,
+ index) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n");
+ goto unlock_out;
+ }
+
+ sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
+ route = &sdinfo->routes[inp_index];
+ if (route && sdinfo->can_route) {
+ input = route->input;
+ output = route->output;
+ }
+
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_routing, input, output, 0);
+
+ if (ret) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "vpfe_doioctl:error in setting input in decoder\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ vpfe_dev->current_subdev = sdinfo;
+ vpfe_dev->current_input = index;
+ vpfe_dev->std_index = 0;
+
+ /* set the bus/interface parameter for the sub device in ccdc */
+ ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
+ if (ret)
+ goto unlock_out;
+
+ /* set the default image parameters in the device */
+ ret = vpfe_config_image_format(vpfe_dev,
+ &vpfe_standards[vpfe_dev->std_index].std_id);
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ sdinfo = vpfe_dev->current_subdev;
+ if (ret)
+ return ret;
+ /* Call querystd function of decoder device */
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, querystd, std_id);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
+
+ /* Call decoder driver function to set the standard */
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ sdinfo = vpfe_dev->current_subdev;
+ /* If streaming is started, return device busy error */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ core, s_std, *std_id);
+ if (ret < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
+ goto unlock_out;
+ }
+ ret = vpfe_config_image_format(vpfe_dev, std_id);
+
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
+
+ *std_id = vpfe_standards[vpfe_dev->std_index].std_id;
+ return 0;
+}
+/*
+ * Videobuf operations
+ */
+static int vpfe_videobuf_setup(struct videobuf_queue *vq,
+ unsigned int *count,
+ unsigned int *size)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
+ *size = config_params.device_bufsize;
+
+ if (*count < config_params.min_numbuffers)
+ *count = config_params.min_numbuffers;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "count=%d, size=%d\n", *count, *size);
+ return 0;
+}
+
+static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
+
+ /* If buffer is not initialized, initialize it */
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = vpfe_dev->fmt.fmt.pix.width;
+ vb->height = vpfe_dev->fmt.fmt.pix.height;
+ vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+ vb->field = field;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+}
+
+static void vpfe_videobuf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ /* Get the file handle object and device object */
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+ unsigned long flags;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n");
+
+ /* add the buffer to the DMA queue */
+ spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+ list_add_tail(&vb->queue, &vpfe_dev->dma_queue);
+ spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+
+ /* Change state of the buffer */
+ vb->state = VIDEOBUF_QUEUED;
+}
+
+static void vpfe_videobuf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+ unsigned long flags;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
+
+ /*
+ * We need to flush the buffer from the dma queue since
+ * they are de-allocated
+ */
+ spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+ INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+ spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vpfe_videobuf_qops = {
+ .buf_setup = vpfe_videobuf_setup,
+ .buf_prepare = vpfe_videobuf_prepare,
+ .buf_queue = vpfe_videobuf_queue,
+ .buf_release = vpfe_videobuf_release,
+};
+
+/*
+ * vpfe_reqbufs. currently support REQBUF only once opening
+ * the device.
+ */
+static int vpfe_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req_buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ if (V4L2_MEMORY_USERPTR == req_buf->memory) {
+ /* we don't support user ptr IO */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs:"
+ " USERPTR IO not supported\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ if (vpfe_dev->io_usrs != 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ vpfe_dev->memory = req_buf->memory;
+ videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue,
+ &vpfe_videobuf_qops,
+ NULL,
+ &vpfe_dev->irqlock,
+ req_buf->type,
+ vpfe_dev->fmt.fmt.pix.field,
+ sizeof(struct videobuf_buffer),
+ fh);
+
+ fh->io_allowed = 1;
+ vpfe_dev->io_usrs = 1;
+ INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+ ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf);
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ if (vpfe_dev->memory != V4L2_MEMORY_MMAP) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
+ return -EINVAL;
+ }
+ /* Call videobuf_querybuf to get information */
+ return videobuf_querybuf(&vpfe_dev->buffer_queue, buf);
+}
+
+static int vpfe_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /*
+ * If this file handle is not allowed to do IO,
+ * return error
+ */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+ return videobuf_qbuf(&vpfe_dev->buffer_queue, p);
+}
+
+static int vpfe_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+ return videobuf_dqbuf(&vpfe_dev->buffer_queue,
+ buf, file->f_flags & O_NONBLOCK);
+}
+
+/*
+ * vpfe_calculate_offsets : This function calculates buffers offset
+ * for top and bottom field
+ */
+static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev)
+{
+ struct v4l2_rect image_win;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n");
+
+ ccdc_dev->hw_ops.get_image_window(&image_win);
+ vpfe_dev->field_off = image_win.height * image_win.width;
+}
+
+/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */
+static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+ ccdc_dev->hw_ops.enable(1);
+ if (ccdc_dev->hw_ops.enable_out_to_sdram)
+ ccdc_dev->hw_ops.enable_out_to_sdram(1);
+ vpfe_dev->started = 1;
+}
+
+/*
+ * vpfe_streamon. Assume the DMA queue is not empty.
+ * application is expected to call QBUF before calling
+ * this ioctl. If not, driver returns error
+ */
+static int vpfe_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ unsigned long addr;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /* If file handle is not allowed IO, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_stream, 1);
+
+ if (ret && (ret != -ENOIOCTLCMD)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n");
+ return -EINVAL;
+ }
+
+ /* If buffer queue is empty, return error */
+ if (list_empty(&vpfe_dev->buffer_queue.stream)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
+ return -EIO;
+ }
+
+ /* Call videobuf_streamon to start streaming * in videobuf */
+ ret = videobuf_streamon(&vpfe_dev->buffer_queue);
+ if (ret)
+ return ret;
+
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ goto streamoff;
+ /* Get the next frame from the buffer queue */
+ vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+ struct videobuf_buffer, queue);
+ vpfe_dev->cur_frm = vpfe_dev->next_frm;
+ /* Remove buffer from the buffer queue */
+ list_del(&vpfe_dev->cur_frm->queue);
+ /* Mark state of the current frame to active */
+ vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE;
+ /* Initialize field_id and started member */
+ vpfe_dev->field_id = 0;
+ addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+
+ /* Calculate field offset */
+ vpfe_calculate_offsets(vpfe_dev);
+
+ if (vpfe_attach_irq(vpfe_dev) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in attaching interrupt handle\n");
+ ret = -EFAULT;
+ goto unlock_out;
+ }
+ if (ccdc_dev->hw_ops.configure() < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in configuring ccdc\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr));
+ vpfe_start_ccdc_capture(vpfe_dev);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+streamoff:
+ ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+ return ret;
+}
+
+static int vpfe_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /* If io is allowed for this file handle, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ /* If streaming is not started, return error */
+ if (!vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "device started\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ vpfe_stop_ccdc_capture(vpfe_dev);
+ vpfe_detach_irq(vpfe_dev);
+
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_stream, 0);
+
+ if (ret && (ret != -ENOIOCTLCMD))
+ v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n");
+ ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
+
+ if (vpfe_dev->std_index > ARRAY_SIZE(vpfe_standards))
+ return -EINVAL;
+
+ memset(crop, 0, sizeof(struct v4l2_cropcap));
+ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ crop->bounds.width = crop->defrect.width =
+ vpfe_standards[vpfe_dev->std_index].width;
+ crop->bounds.height = crop->defrect.height =
+ vpfe_standards[vpfe_dev->std_index].height;
+ crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
+ return 0;
+}
+
+static int vpfe_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n");
+
+ crop->c = vpfe_dev->crop;
+ return 0;
+}
+
+static int vpfe_s_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n");
+
+ if (vpfe_dev->started) {
+ /* make sure streaming is not started */
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Cannot change crop when streaming is ON\n");
+ return -EBUSY;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ if (crop->c.top < 0 || crop->c.left < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "doesn't support negative values for top & left\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ /* adjust the width to 16 pixel boundry */
+ crop->c.width = ((crop->c.width + 15) & ~0xf);
+
+ /* make sure parameters are valid */
+ if ((crop->c.left + crop->c.width >
+ vpfe_dev->std_info.active_pixels) ||
+ (crop->c.top + crop->c.height >
+ vpfe_dev->std_info.active_lines)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ ccdc_dev->hw_ops.set_image_window(&crop->c);
+ vpfe_dev->fmt.fmt.pix.width = crop->c.width;
+ vpfe_dev->fmt.fmt.pix.height = crop->c.height;
+ vpfe_dev->fmt.fmt.pix.bytesperline =
+ ccdc_dev->hw_ops.get_line_length();
+ vpfe_dev->fmt.fmt.pix.sizeimage =
+ vpfe_dev->fmt.fmt.pix.bytesperline *
+ vpfe_dev->fmt.fmt.pix.height;
+ vpfe_dev->crop = crop->c;
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+
+static long vpfe_param_handler(struct file *file, void *priv,
+ int cmd, void *param)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n");
+
+ if (vpfe_dev->started) {
+ /* only allowed if streaming is not started */
+ v4l2_err(&vpfe_dev->v4l2_dev, "device already started\n");
+ return -EBUSY;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ switch (cmd) {
+ case VPFE_CMD_S_CCDC_RAW_PARAMS:
+ v4l2_warn(&vpfe_dev->v4l2_dev,
+ "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
+ ret = ccdc_dev->hw_ops.set_params(param);
+ if (ret) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in setting parameters in CCDC\n");
+ goto unlock_out;
+ }
+ if (vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Invalid image format at CCDC\n");
+ goto unlock_out;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+
+/* vpfe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
+ .vidioc_querycap = vpfe_querycap,
+ .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap,
+ .vidioc_enum_input = vpfe_enum_input,
+ .vidioc_g_input = vpfe_g_input,
+ .vidioc_s_input = vpfe_s_input,
+ .vidioc_querystd = vpfe_querystd,
+ .vidioc_s_std = vpfe_s_std,
+ .vidioc_g_std = vpfe_g_std,
+ .vidioc_reqbufs = vpfe_reqbufs,
+ .vidioc_querybuf = vpfe_querybuf,
+ .vidioc_qbuf = vpfe_qbuf,
+ .vidioc_dqbuf = vpfe_dqbuf,
+ .vidioc_streamon = vpfe_streamon,
+ .vidioc_streamoff = vpfe_streamoff,
+ .vidioc_cropcap = vpfe_cropcap,
+ .vidioc_g_crop = vpfe_g_crop,
+ .vidioc_s_crop = vpfe_s_crop,
+ .vidioc_default = vpfe_param_handler,
+};
+
+static struct vpfe_device *vpfe_initialize(void)
+{
+ struct vpfe_device *vpfe_dev;
+
+ /* Default number of buffers should be 3 */
+ if ((numbuffers > 0) &&
+ (numbuffers < config_params.min_numbuffers))
+ numbuffers = config_params.min_numbuffers;
+
+ /*
+ * Set buffer size to min buffers size if invalid buffer size is
+ * given
+ */
+ if (bufsize < config_params.min_bufsize)
+ bufsize = config_params.min_bufsize;
+
+ config_params.numbuffers = numbuffers;
+
+ if (numbuffers)
+ config_params.device_bufsize = bufsize;
+
+ /* Allocate memory for device objects */
+ vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL);
+
+ return vpfe_dev;
+}
+
+static void vpfe_disable_clock(struct vpfe_device *vpfe_dev)
+{
+ struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
+
+ clk_disable(vpfe_cfg->vpssclk);
+ clk_put(vpfe_cfg->vpssclk);
+ clk_disable(vpfe_cfg->slaveclk);
+ clk_put(vpfe_cfg->slaveclk);
+ v4l2_info(vpfe_dev->pdev->driver,
+ "vpfe vpss master & slave clocks disabled\n");
+}
+
+static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
+{
+ struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
+ int ret = -ENOENT;
+
+ vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master");
+ if (NULL == vpfe_cfg->vpssclk) {
+ v4l2_err(vpfe_dev->pdev->driver, "No clock defined for"
+ "vpss_master\n");
+ return ret;
+ }
+
+ if (clk_enable(vpfe_cfg->vpssclk)) {
+ v4l2_err(vpfe_dev->pdev->driver,
+ "vpfe vpss master clock not enabled\n");
+ goto out;
+ }
+ v4l2_info(vpfe_dev->pdev->driver,
+ "vpfe vpss master clock enabled\n");
+
+ vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave");
+ if (NULL == vpfe_cfg->slaveclk) {
+ v4l2_err(vpfe_dev->pdev->driver,
+ "No clock defined for vpss slave\n");
+ goto out;
+ }
+
+ if (clk_enable(vpfe_cfg->slaveclk)) {
+ v4l2_err(vpfe_dev->pdev->driver,
+ "vpfe vpss slave clock not enabled\n");
+ goto out;
+ }
+ v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n");
+ return 0;
+out:
+ if (vpfe_cfg->vpssclk)
+ clk_put(vpfe_cfg->vpssclk);
+ if (vpfe_cfg->slaveclk)
+ clk_put(vpfe_cfg->slaveclk);
+
+ return -1;
+}
+
+/*
+ * vpfe_probe : This function creates device entries by register
+ * itself to the V4L2 driver and initializes fields of each
+ * device objects
+ */
+static __init int vpfe_probe(struct platform_device *pdev)
+{
+ struct vpfe_subdev_info *sdinfo;
+ struct vpfe_config *vpfe_cfg;
+ struct resource *res1;
+ struct vpfe_device *vpfe_dev;
+ struct i2c_adapter *i2c_adap;
+ struct video_device *vfd;
+ int ret = -ENOMEM, i, j;
+ int num_subdevs = 0;
+
+ /* Get the pointer to the device object */
+ vpfe_dev = vpfe_initialize();
+
+ if (!vpfe_dev) {
+ v4l2_err(pdev->dev.driver,
+ "Failed to allocate memory for vpfe_dev\n");
+ return ret;
+ }
+
+ vpfe_dev->pdev = &pdev->dev;
+
+ if (NULL == pdev->dev.platform_data) {
+ v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
+ ret = -ENOENT;
+ goto probe_free_dev_mem;
+ }
+
+ vpfe_cfg = pdev->dev.platform_data;
+ vpfe_dev->cfg = vpfe_cfg;
+ if (NULL == vpfe_cfg->ccdc ||
+ NULL == vpfe_cfg->card_name ||
+ NULL == vpfe_cfg->sub_devs) {
+ v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n");
+ ret = -ENOENT;
+ goto probe_free_dev_mem;
+ }
+
+ /* enable vpss clocks */
+ ret = vpfe_enable_clock(vpfe_dev);
+ if (ret)
+ goto probe_free_dev_mem;
+
+ mutex_lock(&ccdc_lock);
+ /* Allocate memory for ccdc configuration */
+ ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL);
+ if (NULL == ccdc_cfg) {
+ v4l2_err(pdev->dev.driver,
+ "Memory allocation failed for ccdc_cfg\n");
+ goto probe_disable_clock;
+ }
+
+ strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
+ /* Get VINT0 irq resource */
+ res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get interrupt for VINT0\n");
+ ret = -ENOENT;
+ goto probe_disable_clock;
+ }
+ vpfe_dev->ccdc_irq0 = res1->start;
+
+ /* Get VINT1 irq resource */
+ res1 = platform_get_resource(pdev,
+ IORESOURCE_IRQ, 1);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get interrupt for VINT1\n");
+ ret = -ENOENT;
+ goto probe_disable_clock;
+ }
+ vpfe_dev->ccdc_irq1 = res1->start;
+
+ /* Get address base of CCDC */
+ res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get register address map\n");
+ ret = -ENOENT;
+ goto probe_disable_clock;
+ }
+
+ ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1;
+ if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size,
+ pdev->dev.driver->name)) {
+ v4l2_err(pdev->dev.driver,
+ "Failed request_mem_region for ccdc base\n");
+ ret = -ENXIO;
+ goto probe_disable_clock;
+ }
+ ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start,
+ ccdc_cfg->ccdc_addr_size);
+ if (!ccdc_cfg->ccdc_addr) {
+ v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc addr\n");
+ ret = -ENXIO;
+ goto probe_out_release_mem1;
+ }
+
+ ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
+ "vpfe_capture0", vpfe_dev);
+
+ if (0 != ret) {
+ v4l2_err(pdev->dev.driver, "Unable to request interrupt\n");
+ goto probe_out_unmap1;
+ }
+
+ /* Allocate memory for video device */
+ vfd = video_device_alloc();
+ if (NULL == vfd) {
+ ret = -ENOMEM;
+ v4l2_err(pdev->dev.driver,
+ "Unable to alloc video device\n");
+ goto probe_out_release_irq;
+ }
+
+ /* Initialize field of video device */
+ vfd->release = video_device_release;
+ vfd->fops = &vpfe_fops;
+ vfd->ioctl_ops = &vpfe_ioctl_ops;
+ vfd->minor = -1;
+ vfd->tvnorms = 0;
+ vfd->current_norm = V4L2_STD_PAL;
+ vfd->v4l2_dev = &vpfe_dev->v4l2_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "%s_V%d.%d.%d",
+ CAPTURE_DRV_NAME,
+ (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff,
+ (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff,
+ (VPFE_CAPTURE_VERSION_CODE) & 0xff);
+ /* Set video_dev to the video device */
+ vpfe_dev->video_dev = vfd;
+
+ ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
+ if (ret) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to register v4l2 device.\n");
+ goto probe_out_video_release;
+ }
+ v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
+ spin_lock_init(&vpfe_dev->irqlock);
+ spin_lock_init(&vpfe_dev->dma_queue_lock);
+ mutex_init(&vpfe_dev->lock);
+
+ /* Initialize field of the device objects */
+ vpfe_dev->numbuffers = config_params.numbuffers;
+
+ /* Initialize prio member of device object */
+ v4l2_prio_init(&vpfe_dev->prio);
+ /* register video device */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "trying to register vpfe device.\n");
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "video_dev=%x\n", (int)&vpfe_dev->video_dev);
+ vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ret = video_register_device(vpfe_dev->video_dev,
+ VFL_TYPE_GRABBER, -1);
+
+ if (ret) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to register video device.\n");
+ goto probe_out_v4l2_unregister;
+ }
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n");
+ /* set the driver data in platform device */
+ platform_set_drvdata(pdev, vpfe_dev);
+ /* set driver private data */
+ video_set_drvdata(vpfe_dev->video_dev, vpfe_dev);
+ i2c_adap = i2c_get_adapter(1);
+ vpfe_cfg = pdev->dev.platform_data;
+ num_subdevs = vpfe_cfg->num_subdevs;
+ vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs,
+ GFP_KERNEL);
+ if (NULL == vpfe_dev->sd) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "unable to allocate memory for subdevice pointers\n");
+ ret = -ENOMEM;
+ goto probe_out_video_unregister;
+ }
+
+ for (i = 0; i < num_subdevs; i++) {
+ struct v4l2_input *inps;
+
+ sdinfo = &vpfe_cfg->sub_devs[i];
+
+ /* Load up the subdevice */
+ vpfe_dev->sd[i] =
+ v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+ i2c_adap,
+ sdinfo->name,
+ &sdinfo->board_info,
+ NULL);
+ if (vpfe_dev->sd[i]) {
+ v4l2_info(&vpfe_dev->v4l2_dev,
+ "v4l2 sub device %s registered\n",
+ sdinfo->name);
+ vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
+ /* update tvnorms from the sub devices */
+ for (j = 0; j < sdinfo->num_inputs; j++) {
+ inps = &sdinfo->inputs[j];
+ vfd->tvnorms |= inps->std;
+ }
+ } else {
+ v4l2_info(&vpfe_dev->v4l2_dev,
+ "v4l2 sub device %s register fails\n",
+ sdinfo->name);
+ goto probe_sd_out;
+ }
+ }
+
+ /* set first sub device as current one */
+ vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
+
+ /* We have at least one sub device to work with */
+ mutex_unlock(&ccdc_lock);
+ return 0;
+
+probe_sd_out:
+ kfree(vpfe_dev->sd);
+probe_out_video_unregister:
+ video_unregister_device(vpfe_dev->video_dev);
+probe_out_v4l2_unregister:
+ v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+probe_out_video_release:
+ if (vpfe_dev->video_dev->minor == -1)
+ video_device_release(vpfe_dev->video_dev);
+probe_out_release_irq:
+ free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+probe_out_unmap1:
+ iounmap(ccdc_cfg->ccdc_addr);
+probe_out_release_mem1:
+ release_mem_region(res1->start, res1->end - res1->start + 1);
+probe_disable_clock:
+ vpfe_disable_clock(vpfe_dev);
+ mutex_unlock(&ccdc_lock);
+ kfree(ccdc_cfg);
+probe_free_dev_mem:
+ kfree(vpfe_dev);
+ return ret;
+}
+
+/*
+ * vpfe_remove : It un-register device from V4L2 driver
+ */
+static int vpfe_remove(struct platform_device *pdev)
+{
+ struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ v4l2_info(pdev->dev.driver, "vpfe_remove\n");
+
+ free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+ kfree(vpfe_dev->sd);
+ v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+ video_unregister_device(vpfe_dev->video_dev);
+ mutex_lock(&ccdc_lock);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+ iounmap(ccdc_cfg->ccdc_addr);
+ mutex_unlock(&ccdc_lock);
+ vpfe_disable_clock(vpfe_dev);
+ kfree(vpfe_dev);
+ kfree(ccdc_cfg);
+ return 0;
+}
+
+static int
+vpfe_suspend(struct device *dev)
+{
+ /* add suspend code here later */
+ return -1;
+}
+
+static int
+vpfe_resume(struct device *dev)
+{
+ /* add resume code here later */
+ return -1;
+}
+
+static struct dev_pm_ops vpfe_dev_pm_ops = {
+ .suspend = vpfe_suspend,
+ .resume = vpfe_resume,
+};
+
+static struct platform_driver vpfe_driver = {
+ .driver = {
+ .name = CAPTURE_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &vpfe_dev_pm_ops,
+ },
+ .probe = vpfe_probe,
+ .remove = __devexit_p(vpfe_remove),
+};
+
+static __init int vpfe_init(void)
+{
+ printk(KERN_NOTICE "vpfe_init\n");
+ /* Register driver to the kernel */
+ return platform_driver_register(&vpfe_driver);
+}
+
+/*
+ * vpfe_cleanup : This function un-registers device driver
+ */
+static void vpfe_cleanup(void)
+{
+ platform_driver_unregister(&vpfe_driver);
+}
+
+module_init(vpfe_init);
+module_exit(vpfe_cleanup);
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c
new file mode 100644
index 000000000000..aa771268a5a5
--- /dev/null
+++ b/drivers/media/video/davinci/vpif.c
@@ -0,0 +1,234 @@
+/*
+ * vpif - DM646x Video Port Interface driver
+ * VPIF is a receiver and transmitter for video data. It has two channels(0, 1)
+ * that receiveing video byte stream and two channels(2, 3) for video output.
+ * The hardware supports SDTV, HDTV formats, raw data capture.
+ * Currently, the driver supports NTSC and PAL standards.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
+MODULE_LICENSE("GPL");
+
+#define VPIF_CH0_MAX_MODES (22)
+#define VPIF_CH1_MAX_MODES (02)
+#define VPIF_CH2_MAX_MODES (15)
+#define VPIF_CH3_MAX_MODES (02)
+
+static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
+{
+ if (val)
+ vpif_set_bit(reg, bit);
+ else
+ vpif_clr_bit(reg, bit);
+}
+
+/* This structure is used to keep track of VPIF size register's offsets */
+struct vpif_registers {
+ u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl;
+ u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt;
+ u32 vanc1_size, width_mask, len_mask;
+ u8 max_modes;
+};
+
+static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = {
+ /* Channel0 */
+ {
+ VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01,
+ VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL,
+ VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+ VPIF_CH0_MAX_MODES,
+ },
+ /* Channel1 */
+ {
+ VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01,
+ VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL,
+ VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+ VPIF_CH1_MAX_MODES,
+ },
+ /* Channel2 */
+ {
+ VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01,
+ VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL,
+ VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE,
+ VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF,
+ VPIF_CH2_MAX_MODES
+ },
+ /* Channel3 */
+ {
+ VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01,
+ VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL,
+ VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE,
+ VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF,
+ VPIF_CH3_MAX_MODES
+ },
+};
+
+/* vpif_set_mode_info:
+ * This function is used to set horizontal and vertical config parameters
+ * As per the standard in the channel, configure the values of L1, L3,
+ * L5, L7 L9, L11 in VPIF Register , also write width and height
+ */
+static void vpif_set_mode_info(const struct vpif_channel_config_params *config,
+ u8 channel_id, u8 config_channel_id)
+{
+ u32 value;
+
+ value = (config->eav2sav & vpifregs[config_channel_id].width_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->sav2eav & vpifregs[config_channel_id].width_mask);
+ regw(value, vpifregs[channel_id].h_cfg);
+
+ value = (config->l1 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l3 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_00);
+
+ value = (config->l5 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l7 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_01);
+
+ value = (config->l9 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l11 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_02);
+
+ value = (config->vsize & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg);
+}
+
+/* config_vpif_params
+ * Function to set the parameters of a channel
+ * Mainly modifies the channel ciontrol register
+ * It sets frame format, yc mux mode
+ */
+static void config_vpif_params(struct vpif_params *vpifparams,
+ u8 channel_id, u8 found)
+{
+ const struct vpif_channel_config_params *config = &vpifparams->std_info;
+ u32 value, ch_nip, reg;
+ u8 start, end;
+ int i;
+
+ start = channel_id;
+ end = channel_id + found;
+
+ for (i = start; i < end; i++) {
+ reg = vpifregs[i].ch_ctrl;
+ if (channel_id < 2)
+ ch_nip = VPIF_CAPTURE_CH_NIP;
+ else
+ ch_nip = VPIF_DISPLAY_CH_NIP;
+
+ vpif_wr_bit(reg, ch_nip, config->frm_fmt);
+ vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode);
+ vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT,
+ vpifparams->video_params.storage_mode);
+
+ /* Set raster scanning SDR Format */
+ vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT);
+ vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format);
+
+ if (channel_id > 1) /* Set the Pixel enable bit */
+ vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT);
+ else if (config->capture_format) {
+ /* Set the polarity of various pins */
+ vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT,
+ vpifparams->params.raw_params.fid_pol);
+ vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT,
+ vpifparams->params.raw_params.vd_pol);
+ vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT,
+ vpifparams->params.raw_params.hd_pol);
+
+ value = regr(reg);
+ /* Set data width */
+ value &= ((~(unsigned int)(0x3)) <<
+ VPIF_CH_DATA_WIDTH_BIT);
+ value |= ((vpifparams->params.raw_params.data_sz) <<
+ VPIF_CH_DATA_WIDTH_BIT);
+ regw(value, reg);
+ }
+
+ /* Write the pitch in the driver */
+ regw((vpifparams->video_params.hpitch),
+ vpifregs[i].line_offset);
+ }
+}
+
+/* vpif_set_video_params
+ * This function is used to set video parameters in VPIF register
+ */
+int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id)
+{
+ const struct vpif_channel_config_params *config = &vpifparams->std_info;
+ int found = 1;
+
+ vpif_set_mode_info(config, channel_id, channel_id);
+ if (!config->ycmux_mode) {
+ /* YC are on separate channels (HDTV formats) */
+ vpif_set_mode_info(config, channel_id + 1, channel_id);
+ found = 2;
+ }
+
+ config_vpif_params(vpifparams, channel_id, found);
+
+ regw(0x80, VPIF_REQ_SIZE);
+ regw(0x01, VPIF_EMULATION_CTRL);
+
+ return found;
+}
+EXPORT_SYMBOL(vpif_set_video_params);
+
+void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
+ u8 channel_id)
+{
+ u32 value;
+
+ value = 0x3F8 & (vbiparams->hstart0);
+ value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16);
+ regw(value, vpifregs[channel_id].vanc0_strt);
+
+ value = 0x3F8 & (vbiparams->hstart1);
+ value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16);
+ regw(value, vpifregs[channel_id].vanc1_strt);
+
+ value = 0x3F8 & (vbiparams->hsize0);
+ value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16);
+ regw(value, vpifregs[channel_id].vanc0_size);
+
+ value = 0x3F8 & (vbiparams->hsize1);
+ value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16);
+ regw(value, vpifregs[channel_id].vanc1_size);
+
+}
+EXPORT_SYMBOL(vpif_set_vbi_display_params);
+
+int vpif_channel_getfid(u8 channel_id)
+{
+ return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK)
+ >> VPIF_CH_FID_SHIFT;
+}
+EXPORT_SYMBOL(vpif_channel_getfid);
+
+void vpif_base_addr_init(void __iomem *base)
+{
+ vpif_base = base;
+}
+EXPORT_SYMBOL(vpif_base_addr_init);
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h
new file mode 100644
index 000000000000..fca26dcb54de
--- /dev/null
+++ b/drivers/media/video/davinci/vpif.h
@@ -0,0 +1,632 @@
+/*
+ * VPIF header file
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef VPIF_H
+#define VPIF_H
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <mach/hardware.h>
+
+/* Maximum channel allowed */
+#define VPIF_NUM_CHANNELS (4)
+#define VPIF_CAPTURE_NUM_CHANNELS (2)
+#define VPIF_DISPLAY_NUM_CHANNELS (2)
+
+/* Macros to read/write registers */
+static void __iomem *vpif_base;
+#define regr(reg) readl((reg) + vpif_base)
+#define regw(value, reg) writel(value, (reg + vpif_base))
+
+/* Register Addresss Offsets */
+#define VPIF_PID (0x0000)
+#define VPIF_CH0_CTRL (0x0004)
+#define VPIF_CH1_CTRL (0x0008)
+#define VPIF_CH2_CTRL (0x000C)
+#define VPIF_CH3_CTRL (0x0010)
+
+#define VPIF_INTEN (0x0020)
+#define VPIF_INTEN_SET (0x0024)
+#define VPIF_INTEN_CLR (0x0028)
+#define VPIF_STATUS (0x002C)
+#define VPIF_STATUS_CLR (0x0030)
+#define VPIF_EMULATION_CTRL (0x0034)
+#define VPIF_REQ_SIZE (0x0038)
+
+#define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040)
+#define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044)
+#define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048)
+#define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c)
+#define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050)
+#define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054)
+#define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058)
+#define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c)
+#define VPIF_CH0_SP_CFG (0x0060)
+#define VPIF_CH0_IMG_ADD_OFST (0x0064)
+#define VPIF_CH0_HANC_ADD_OFST (0x0068)
+#define VPIF_CH0_H_CFG (0x006c)
+#define VPIF_CH0_V_CFG_00 (0x0070)
+#define VPIF_CH0_V_CFG_01 (0x0074)
+#define VPIF_CH0_V_CFG_02 (0x0078)
+#define VPIF_CH0_V_CFG_03 (0x007c)
+
+#define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080)
+#define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084)
+#define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088)
+#define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c)
+#define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090)
+#define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094)
+#define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098)
+#define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c)
+#define VPIF_CH1_SP_CFG (0x00a0)
+#define VPIF_CH1_IMG_ADD_OFST (0x00a4)
+#define VPIF_CH1_HANC_ADD_OFST (0x00a8)
+#define VPIF_CH1_H_CFG (0x00ac)
+#define VPIF_CH1_V_CFG_00 (0x00b0)
+#define VPIF_CH1_V_CFG_01 (0x00b4)
+#define VPIF_CH1_V_CFG_02 (0x00b8)
+#define VPIF_CH1_V_CFG_03 (0x00bc)
+
+#define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0)
+#define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4)
+#define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8)
+#define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc)
+#define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0)
+#define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4)
+#define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8)
+#define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc)
+#define VPIF_CH2_SP_CFG (0x00e0)
+#define VPIF_CH2_IMG_ADD_OFST (0x00e4)
+#define VPIF_CH2_HANC_ADD_OFST (0x00e8)
+#define VPIF_CH2_H_CFG (0x00ec)
+#define VPIF_CH2_V_CFG_00 (0x00f0)
+#define VPIF_CH2_V_CFG_01 (0x00f4)
+#define VPIF_CH2_V_CFG_02 (0x00f8)
+#define VPIF_CH2_V_CFG_03 (0x00fc)
+#define VPIF_CH2_HANC0_STRT (0x0100)
+#define VPIF_CH2_HANC0_SIZE (0x0104)
+#define VPIF_CH2_HANC1_STRT (0x0108)
+#define VPIF_CH2_HANC1_SIZE (0x010c)
+#define VPIF_CH2_VANC0_STRT (0x0110)
+#define VPIF_CH2_VANC0_SIZE (0x0114)
+#define VPIF_CH2_VANC1_STRT (0x0118)
+#define VPIF_CH2_VANC1_SIZE (0x011c)
+
+#define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140)
+#define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144)
+#define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148)
+#define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c)
+#define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150)
+#define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154)
+#define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158)
+#define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c)
+#define VPIF_CH3_SP_CFG (0x0160)
+#define VPIF_CH3_IMG_ADD_OFST (0x0164)
+#define VPIF_CH3_HANC_ADD_OFST (0x0168)
+#define VPIF_CH3_H_CFG (0x016c)
+#define VPIF_CH3_V_CFG_00 (0x0170)
+#define VPIF_CH3_V_CFG_01 (0x0174)
+#define VPIF_CH3_V_CFG_02 (0x0178)
+#define VPIF_CH3_V_CFG_03 (0x017c)
+#define VPIF_CH3_HANC0_STRT (0x0180)
+#define VPIF_CH3_HANC0_SIZE (0x0184)
+#define VPIF_CH3_HANC1_STRT (0x0188)
+#define VPIF_CH3_HANC1_SIZE (0x018c)
+#define VPIF_CH3_VANC0_STRT (0x0190)
+#define VPIF_CH3_VANC0_SIZE (0x0194)
+#define VPIF_CH3_VANC1_STRT (0x0198)
+#define VPIF_CH3_VANC1_SIZE (0x019c)
+
+#define VPIF_IODFT_CTRL (0x01c0)
+
+/* Functions for bit Manipulation */
+static inline void vpif_set_bit(u32 reg, u32 bit)
+{
+ regw((regr(reg)) | (0x01 << bit), reg);
+}
+
+static inline void vpif_clr_bit(u32 reg, u32 bit)
+{
+ regw(((regr(reg)) & ~(0x01 << bit)), reg);
+}
+
+/* Macro for Generating mask */
+#ifdef GENERATE_MASK
+#undef GENERATE_MASK
+#endif
+
+#define GENERATE_MASK(bits, pos) \
+ ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos)
+
+/* Bit positions in the channel control registers */
+#define VPIF_CH_DATA_MODE_BIT (2)
+#define VPIF_CH_YC_MUX_BIT (3)
+#define VPIF_CH_SDR_FMT_BIT (4)
+#define VPIF_CH_HANC_EN_BIT (8)
+#define VPIF_CH_VANC_EN_BIT (9)
+
+#define VPIF_CAPTURE_CH_NIP (10)
+#define VPIF_DISPLAY_CH_NIP (11)
+
+#define VPIF_DISPLAY_PIX_EN_BIT (10)
+
+#define VPIF_CH_INPUT_FIELD_FRAME_BIT (12)
+
+#define VPIF_CH_FID_POLARITY_BIT (15)
+#define VPIF_CH_V_VALID_POLARITY_BIT (14)
+#define VPIF_CH_H_VALID_POLARITY_BIT (13)
+#define VPIF_CH_DATA_WIDTH_BIT (28)
+
+#define VPIF_CH_CLK_EDGE_CTRL_BIT (31)
+
+/* Mask various length */
+#define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0)
+#define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0)
+#define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0)
+#define VPIF_CH_LEN_SHIFT (16)
+
+/* VPIF masks for registers */
+#define VPIF_REQ_SIZE_MASK (0x1ff)
+
+/* bit posotion of interrupt vpif_ch_intr register */
+#define VPIF_INTEN_FRAME_CH0 (0x00000001)
+#define VPIF_INTEN_FRAME_CH1 (0x00000002)
+#define VPIF_INTEN_FRAME_CH2 (0x00000004)
+#define VPIF_INTEN_FRAME_CH3 (0x00000008)
+
+/* bit position of clock and channel enable in vpif_chn_ctrl register */
+
+#define VPIF_CH0_CLK_EN (0x00000002)
+#define VPIF_CH0_EN (0x00000001)
+#define VPIF_CH1_CLK_EN (0x00000002)
+#define VPIF_CH1_EN (0x00000001)
+#define VPIF_CH2_CLK_EN (0x00000002)
+#define VPIF_CH2_EN (0x00000001)
+#define VPIF_CH3_CLK_EN (0x00000002)
+#define VPIF_CH3_EN (0x00000001)
+#define VPIF_CH_CLK_EN (0x00000002)
+#define VPIF_CH_EN (0x00000001)
+
+#define VPIF_INT_TOP (0x00)
+#define VPIF_INT_BOTTOM (0x01)
+#define VPIF_INT_BOTH (0x02)
+
+#define VPIF_CH0_INT_CTRL_SHIFT (6)
+#define VPIF_CH1_INT_CTRL_SHIFT (6)
+#define VPIF_CH2_INT_CTRL_SHIFT (6)
+#define VPIF_CH3_INT_CTRL_SHIFT (6)
+#define VPIF_CH_INT_CTRL_SHIFT (6)
+
+/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
+#define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
+#define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
+#define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
+#define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL))
+
+#define VPIF_CH_FID_MASK (0x20)
+#define VPIF_CH_FID_SHIFT (5)
+
+#define VPIF_NTSC_VBI_START_FIELD0 (1)
+#define VPIF_NTSC_VBI_START_FIELD1 (263)
+#define VPIF_PAL_VBI_START_FIELD0 (624)
+#define VPIF_PAL_VBI_START_FIELD1 (311)
+
+#define VPIF_NTSC_HBI_START_FIELD0 (1)
+#define VPIF_NTSC_HBI_START_FIELD1 (263)
+#define VPIF_PAL_HBI_START_FIELD0 (624)
+#define VPIF_PAL_HBI_START_FIELD1 (311)
+
+#define VPIF_NTSC_VBI_COUNT_FIELD0 (20)
+#define VPIF_NTSC_VBI_COUNT_FIELD1 (19)
+#define VPIF_PAL_VBI_COUNT_FIELD0 (24)
+#define VPIF_PAL_VBI_COUNT_FIELD1 (25)
+
+#define VPIF_NTSC_HBI_COUNT_FIELD0 (263)
+#define VPIF_NTSC_HBI_COUNT_FIELD1 (262)
+#define VPIF_PAL_HBI_COUNT_FIELD0 (312)
+#define VPIF_PAL_HBI_COUNT_FIELD1 (313)
+
+#define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720)
+#define VPIF_PAL_VBI_SAMPLES_PER_LINE (720)
+#define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268)
+#define VPIF_PAL_HBI_SAMPLES_PER_LINE (280)
+
+#define VPIF_CH_VANC_EN (0x20)
+#define VPIF_DMA_REQ_SIZE (0x080)
+#define VPIF_EMULATION_DISABLE (0x01)
+
+extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS];
+
+/* inline function to enable/disable channel0 */
+static inline void enable_channel0(int enable)
+{
+ if (enable)
+ regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL);
+ else
+ regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL);
+}
+
+/* inline function to enable/disable channel1 */
+static inline void enable_channel1(int enable)
+{
+ if (enable)
+ regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL);
+ else
+ regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL);
+}
+
+/* inline function to enable interrupt for channel0 */
+static inline void channel0_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to enable interrupt for channel1 */
+static inline void channel1_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to set buffer addresses in case of Y/C non mux mode */
+static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for video data */
+static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+
+ regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch0_set_vbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC);
+ regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch0_set_hbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC);
+ regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC);
+}
+
+static inline void ch1_set_vbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC);
+ regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch1_set_hbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC);
+ regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC);
+}
+
+/* Inline function to enable raw vbi in the given channel */
+static inline void disable_raw_feature(u8 channel_id, u8 index)
+{
+ u32 ctrl_reg;
+ if (0 == channel_id)
+ ctrl_reg = VPIF_CH0_CTRL;
+ else
+ ctrl_reg = VPIF_CH1_CTRL;
+
+ if (1 == index)
+ vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
+ else
+ vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
+}
+
+static inline void enable_raw_feature(u8 channel_id, u8 index)
+{
+ u32 ctrl_reg;
+ if (0 == channel_id)
+ ctrl_reg = VPIF_CH0_CTRL;
+ else
+ ctrl_reg = VPIF_CH1_CTRL;
+
+ if (1 == index)
+ vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
+ else
+ vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
+}
+
+/* inline function to enable/disable channel2 */
+static inline void enable_channel2(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
+ regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL);
+ } else {
+ regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
+ regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL);
+ }
+}
+
+/* inline function to enable/disable channel3 */
+static inline void enable_channel3(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
+ regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL);
+ } else {
+ regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
+ regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL);
+ }
+}
+
+/* inline function to enable interrupt for channel2 */
+static inline void channel2_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to enable interrupt for channel3 */
+static inline void channel3_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to enable raw vbi data for channel2 */
+static inline void channel2_raw_enable(int enable, u8 index)
+{
+ u32 mask;
+
+ if (1 == index)
+ mask = VPIF_CH_VANC_EN_BIT;
+ else
+ mask = VPIF_CH_HANC_EN_BIT;
+
+ if (enable)
+ vpif_set_bit(VPIF_CH2_CTRL, mask);
+ else
+ vpif_clr_bit(VPIF_CH2_CTRL, mask);
+}
+
+/* inline function to enable raw vbi data for channel3*/
+static inline void channel3_raw_enable(int enable, u8 index)
+{
+ u32 mask;
+
+ if (1 == index)
+ mask = VPIF_CH_VANC_EN_BIT;
+ else
+ mask = VPIF_CH_HANC_EN_BIT;
+
+ if (enable)
+ vpif_set_bit(VPIF_CH3_CTRL, mask);
+ else
+ vpif_clr_bit(VPIF_CH3_CTRL, mask);
+}
+
+/* inline function to set buffer addresses in case of Y/C non mux mode */
+static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for video data */
+static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for vbi data */
+static inline void ch2_set_vbi_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC);
+ regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch3_set_vbi_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC);
+ regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC);
+}
+
+#define VPIF_MAX_NAME (30)
+
+/* This structure will store size parameters as per the mode selected by user */
+struct vpif_channel_config_params {
+ char name[VPIF_MAX_NAME]; /* Name of the mode */
+ u16 width; /* Indicates width of the image */
+ u16 height; /* Indicates height of the image */
+ u8 fps;
+ u8 frm_fmt; /* Indicates whether this is interlaced
+ * or progressive format */
+ u8 ycmux_mode; /* Indicates whether this mode requires
+ * single or two channels */
+ u16 eav2sav; /* length of sav 2 eav */
+ u16 sav2eav; /* length of sav 2 eav */
+ u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */
+ u16 vsize; /* Vertical size of the image */
+ u8 capture_format; /* Indicates whether capture format
+ * is in BT or in CCD/CMOS */
+ u8 vbi_supported; /* Indicates whether this mode
+ * supports capturing vbi or not */
+ u8 hd_sd;
+ v4l2_std_id stdid;
+};
+
+struct vpif_interface;
+struct vpif_params;
+struct vpif_vbi_params;
+
+int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id);
+void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
+ u8 channel_id);
+int vpif_channel_getfid(u8 channel_id);
+void vpif_base_addr_init(void __iomem *base);
+
+/* Enumerated data types */
+enum vpif_capture_pinpol {
+ VPIF_CAPTURE_PINPOL_SAME = 0,
+ VPIF_CAPTURE_PINPOL_INVERT = 1
+};
+
+enum data_size {
+ _8BITS = 0,
+ _10BITS,
+ _12BITS,
+};
+
+struct vpif_capture_params_raw {
+ enum data_size data_sz;
+ enum vpif_capture_pinpol fid_pol;
+ enum vpif_capture_pinpol vd_pol;
+ enum vpif_capture_pinpol hd_pol;
+};
+
+/* Structure for vpif parameters for raw vbi data */
+struct vpif_vbi_params {
+ __u32 hstart0; /* Horizontal start of raw vbi data for first field */
+ __u32 vstart0; /* Vertical start of raw vbi data for first field */
+ __u32 hsize0; /* Horizontal size of raw vbi data for first field */
+ __u32 vsize0; /* Vertical size of raw vbi data for first field */
+ __u32 hstart1; /* Horizontal start of raw vbi data for second field */
+ __u32 vstart1; /* Vertical start of raw vbi data for second field */
+ __u32 hsize1; /* Horizontal size of raw vbi data for second field */
+ __u32 vsize1; /* Vertical size of raw vbi data for second field */
+};
+
+/* structure for vpif parameters */
+struct vpif_interface {
+ __u8 storage_mode; /* Indicates field or frame mode */
+ unsigned long hpitch;
+ v4l2_std_id stdid;
+};
+
+struct vpif_params {
+ struct vpif_interface video_params;
+ struct vpif_channel_config_params std_info;
+ union param {
+ struct vpif_vbi_params vbi_params;
+ struct vpif_capture_params_raw raw_params;
+ } params;
+};
+
+#endif /* End of #ifndef VPIF_H */
+
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
new file mode 100644
index 000000000000..8ea65d794dbf
--- /dev/null
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -0,0 +1,1679 @@
+/*
+ * vpif-display - VPIF display driver
+ * Display driver for TI DaVinci VPIF
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/version.h>
+
+#include <asm/irq.h>
+#include <asm/page.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#include <mach/dm646x.h>
+
+#include "vpif_display.h"
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
+MODULE_LICENSE("GPL");
+
+#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)
+
+#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
+#define vpif_dbg(level, debug, fmt, arg...) \
+ v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
+
+static int debug = 1;
+static u32 ch2_numbuffers = 3;
+static u32 ch3_numbuffers = 3;
+static u32 ch2_bufsize = 1920 * 1080 * 2;
+static u32 ch3_bufsize = 720 * 576 * 2;
+
+module_param(debug, int, 0644);
+module_param(ch2_numbuffers, uint, S_IRUGO);
+module_param(ch3_numbuffers, uint, S_IRUGO);
+module_param(ch2_bufsize, uint, S_IRUGO);
+module_param(ch3_bufsize, uint, S_IRUGO);
+
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)");
+MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)");
+MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)");
+MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)");
+
+static struct vpif_config_params config_params = {
+ .min_numbuffers = 3,
+ .numbuffers[0] = 3,
+ .numbuffers[1] = 3,
+ .min_bufsize[0] = 720 * 480 * 2,
+ .min_bufsize[1] = 720 * 480 * 2,
+ .channel_bufsize[0] = 1920 * 1080 * 2,
+ .channel_bufsize[1] = 720 * 576 * 2,
+};
+
+static struct vpif_device vpif_obj = { {NULL} };
+static struct device *vpif_dev;
+
+static const struct vpif_channel_config_params ch_params[] = {
+ {
+ "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
+ 286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
+ },
+ {
+ "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
+ 336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
+ },
+};
+
+/*
+ * vpif_uservirt_to_phys: This function is used to convert user
+ * space virtual address to physical address.
+ */
+static u32 vpif_uservirt_to_phys(u32 virtp)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long physp = 0;
+ struct vm_area_struct *vma;
+
+ vma = find_vma(mm, virtp);
+
+ /* For kernel direct-mapped memory, take the easy way */
+ if (virtp >= PAGE_OFFSET) {
+ physp = virt_to_phys((void *)virtp);
+ } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
+ /* this will catch, kernel-allocated, mmaped-to-usermode addr */
+ physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+ } else {
+ /* otherwise, use get_user_pages() for general userland pages */
+ int res, nr_pages = 1;
+ struct page *pages;
+ down_read(&current->mm->mmap_sem);
+
+ res = get_user_pages(current, current->mm,
+ virtp, nr_pages, 1, 0, &pages, NULL);
+ up_read(&current->mm->mmap_sem);
+
+ if (res == nr_pages) {
+ physp = __pa(page_address(&pages[0]) +
+ (virtp & ~PAGE_MASK));
+ } else {
+ vpif_err("get_user_pages failed\n");
+ return 0;
+ }
+ }
+
+ return physp;
+}
+
+/*
+ * buffer_prepare: This is the callback function called from videobuf_qbuf()
+ * function the buffer is prepared and user space virtual address is converted
+ * into physical address
+ */
+static int vpif_buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct common_obj *common;
+ unsigned long addr;
+
+ common = &fh->channel->common[VPIF_VIDEO_INDEX];
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = common->width;
+ vb->height = common->height;
+ vb->size = vb->width * vb->height;
+ vb->field = field;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+
+ /* if user pointer memory mechanism is used, get the physical
+ * address of the buffer */
+ if (V4L2_MEMORY_USERPTR == common->memory) {
+ if (!vb->baddr) {
+ vpif_err("buffer_address is 0\n");
+ return -EINVAL;
+ }
+
+ vb->boff = vpif_uservirt_to_phys(vb->baddr);
+ if (!ISALIGNED(vb->boff))
+ goto buf_align_exit;
+ }
+
+ addr = vb->boff;
+ if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
+ if (!ISALIGNED(addr + common->ytop_off) ||
+ !ISALIGNED(addr + common->ybtm_off) ||
+ !ISALIGNED(addr + common->ctop_off) ||
+ !ISALIGNED(addr + common->cbtm_off))
+ goto buf_align_exit;
+ }
+ return 0;
+
+buf_align_exit:
+ vpif_err("buffer offset not aligned to 8 bytes\n");
+ return -EINVAL;
+}
+
+/*
+ * vpif_buffer_setup: This function allocates memory for the buffers
+ */
+static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+ unsigned int *size)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (V4L2_MEMORY_MMAP != common->memory)
+ return 0;
+
+ *size = config_params.channel_bufsize[ch->channel_id];
+ if (*count < config_params.min_numbuffers)
+ *count = config_params.min_numbuffers;
+
+ return 0;
+}
+
+/*
+ * vpif_buffer_queue: This function adds the buffer to DMA queue
+ */
+static void vpif_buffer_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct common_obj *common;
+
+ common = &fh->channel->common[VPIF_VIDEO_INDEX];
+
+ /* add the buffer to the DMA queue */
+ list_add_tail(&vb->queue, &common->dma_queue);
+ vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * vpif_buffer_release: This function is called from the videobuf layer to
+ * free memory allocated to the buffers
+ */
+static void vpif_buffer_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ unsigned int buf_size = 0;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ videobuf_dma_contig_free(q, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+
+ if (V4L2_MEMORY_MMAP != common->memory)
+ return;
+
+ buf_size = config_params.channel_bufsize[ch->channel_id];
+}
+
+static struct videobuf_queue_ops video_qops = {
+ .buf_setup = vpif_buffer_setup,
+ .buf_prepare = vpif_buffer_prepare,
+ .buf_queue = vpif_buffer_queue,
+ .buf_release = vpif_buffer_release,
+};
+static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
+
+static void process_progressive_mode(struct common_obj *common)
+{
+ unsigned long addr = 0;
+
+ /* Get the next buffer from buffer queue */
+ common->next_frm = list_entry(common->dma_queue.next,
+ struct videobuf_buffer, queue);
+ /* Remove that buffer from the buffer queue */
+ list_del(&common->next_frm->queue);
+ /* Mark status of the buffer as active */
+ common->next_frm->state = VIDEOBUF_ACTIVE;
+
+ /* Set top and bottom field addrs in VPIF registers */
+ addr = videobuf_to_dma_contig(common->next_frm);
+ common->set_addr(addr + common->ytop_off,
+ addr + common->ybtm_off,
+ addr + common->ctop_off,
+ addr + common->cbtm_off);
+}
+
+static void process_interlaced_mode(int fid, struct common_obj *common)
+{
+ /* device field id and local field id are in sync */
+ /* If this is even field */
+ if (0 == fid) {
+ if (common->cur_frm == common->next_frm)
+ return;
+
+ /* one frame is displayed If next frame is
+ * available, release cur_frm and move on */
+ /* Copy frame display time */
+ do_gettimeofday(&common->cur_frm->ts);
+ /* Change status of the cur_frm */
+ common->cur_frm->state = VIDEOBUF_DONE;
+ /* unlock semaphore on cur_frm */
+ wake_up_interruptible(&common->cur_frm->done);
+ /* Make cur_frm pointing to next_frm */
+ common->cur_frm = common->next_frm;
+
+ } else if (1 == fid) { /* odd field */
+ if (list_empty(&common->dma_queue)
+ || (common->cur_frm != common->next_frm)) {
+ return;
+ }
+ /* one field is displayed configure the next
+ * frame if it is available else hold on current
+ * frame */
+ /* Get next from the buffer queue */
+ process_progressive_mode(common);
+
+ }
+}
+
+/*
+ * vpif_channel_isr: It changes status of the displayed buffer, takes next
+ * buffer from the queue and sets its address in VPIF registers
+ */
+static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
+{
+ struct vpif_device *dev = &vpif_obj;
+ struct channel_obj *ch;
+ struct common_obj *common;
+ enum v4l2_field field;
+ int fid = -1, i;
+ int channel_id = 0;
+
+ channel_id = *(int *)(dev_id);
+ ch = dev->dev[channel_id];
+ field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
+ for (i = 0; i < VPIF_NUMOBJECTS; i++) {
+ common = &ch->common[i];
+ /* If streaming is started in this channel */
+ if (0 == common->started)
+ continue;
+
+ if (1 == ch->vpifparams.std_info.frm_fmt) {
+ if (list_empty(&common->dma_queue))
+ continue;
+
+ /* Progressive mode */
+ if (!channel_first_int[i][channel_id]) {
+ /* Mark status of the cur_frm to
+ * done and unlock semaphore on it */
+ do_gettimeofday(&common->cur_frm->ts);
+ common->cur_frm->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&common->cur_frm->done);
+ /* Make cur_frm pointing to next_frm */
+ common->cur_frm = common->next_frm;
+ }
+
+ channel_first_int[i][channel_id] = 0;
+ process_progressive_mode(common);
+ } else {
+ /* Interlaced mode */
+ /* If it is first interrupt, ignore it */
+
+ if (channel_first_int[i][channel_id]) {
+ channel_first_int[i][channel_id] = 0;
+ continue;
+ }
+
+ if (0 == i) {
+ ch->field_id ^= 1;
+ /* Get field id from VPIF registers */
+ fid = vpif_channel_getfid(ch->channel_id + 2);
+ /* If fid does not match with stored field id */
+ if (fid != ch->field_id) {
+ /* Make them in sync */
+ if (0 == fid)
+ ch->field_id = fid;
+
+ return IRQ_HANDLED;
+ }
+ }
+ process_interlaced_mode(fid, common);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int vpif_get_std_info(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ const struct vpif_channel_config_params *config;
+
+ int index;
+
+ std_info->stdid = vid_ch->stdid;
+ if (!std_info)
+ return -1;
+
+ for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
+ config = &ch_params[index];
+ if (config->stdid & std_info->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ }
+
+ if (index == ARRAY_SIZE(ch_params))
+ return -1;
+
+ common->fmt.fmt.pix.width = std_info->width;
+ common->fmt.fmt.pix.height = std_info->height;
+ vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",
+ common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
+
+ /* Set height and width paramateres */
+ ch->common[VPIF_VIDEO_INDEX].height = std_info->height;
+ ch->common[VPIF_VIDEO_INDEX].width = std_info->width;
+
+ return 0;
+}
+
+/*
+ * vpif_calculate_offsets: This function calculates buffers offset for Y and C
+ * in the top and bottom field
+ */
+static void vpif_calculate_offsets(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ enum v4l2_field field = common->fmt.fmt.pix.field;
+ struct video_obj *vid_ch = &ch->video;
+ unsigned int hpitch, vpitch, sizeimage;
+
+ if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
+ if (ch->vpifparams.std_info.frm_fmt)
+ vid_ch->buf_field = V4L2_FIELD_NONE;
+ else
+ vid_ch->buf_field = V4L2_FIELD_INTERLACED;
+ } else {
+ vid_ch->buf_field = common->fmt.fmt.pix.field;
+ }
+
+ if (V4L2_MEMORY_USERPTR == common->memory)
+ sizeimage = common->fmt.fmt.pix.sizeimage;
+ else
+ sizeimage = config_params.channel_bufsize[ch->channel_id];
+
+ hpitch = common->fmt.fmt.pix.bytesperline;
+ vpitch = sizeimage / (hpitch * 2);
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+ common->ytop_off = 0;
+ common->ybtm_off = hpitch;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = sizeimage / 2 + hpitch;
+ } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
+ common->ytop_off = 0;
+ common->ybtm_off = sizeimage / 4;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = common->ctop_off + sizeimage / 4;
+ } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
+ common->ybtm_off = 0;
+ common->ytop_off = sizeimage / 4;
+ common->cbtm_off = sizeimage / 2;
+ common->ctop_off = common->cbtm_off + sizeimage / 4;
+ }
+
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+ vpifparams->video_params.storage_mode = 1;
+ } else {
+ vpifparams->video_params.storage_mode = 0;
+ }
+
+ if (ch->vpifparams.std_info.frm_fmt == 1) {
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ } else {
+ if ((field == V4L2_FIELD_ANY) ||
+ (field == V4L2_FIELD_INTERLACED))
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline * 2;
+ else
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ }
+
+ ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;
+}
+
+static void vpif_config_format(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
+ if (config_params.numbuffers[ch->channel_id] == 0)
+ common->memory = V4L2_MEMORY_USERPTR;
+ else
+ common->memory = V4L2_MEMORY_MMAP;
+
+ common->fmt.fmt.pix.sizeimage =
+ config_params.channel_bufsize[ch->channel_id];
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
+ common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+}
+
+static int vpif_check_format(struct channel_obj *ch,
+ struct v4l2_pix_format *pixfmt)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ enum v4l2_field field = pixfmt->field;
+ u32 sizeimage, hpitch, vpitch;
+
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
+ goto invalid_fmt_exit;
+
+ if (!(VPIF_VALID_FIELD(field)))
+ goto invalid_fmt_exit;
+
+ if (pixfmt->bytesperline <= 0)
+ goto invalid_pitch_exit;
+
+ if (V4L2_MEMORY_USERPTR == common->memory)
+ sizeimage = pixfmt->sizeimage;
+ else
+ sizeimage = config_params.channel_bufsize[ch->channel_id];
+
+ if (vpif_get_std_info(ch)) {
+ vpif_err("Error getting the standard info\n");
+ return -EINVAL;
+ }
+
+ hpitch = pixfmt->bytesperline;
+ vpitch = sizeimage / (hpitch * 2);
+
+ /* Check for valid value of pitch */
+ if ((hpitch < ch->vpifparams.std_info.width) ||
+ (vpitch < ch->vpifparams.std_info.height))
+ goto invalid_pitch_exit;
+
+ /* Check for 8 byte alignment */
+ if (!ISALIGNED(hpitch)) {
+ vpif_err("invalid pitch alignment\n");
+ return -EINVAL;
+ }
+ pixfmt->width = common->fmt.fmt.pix.width;
+ pixfmt->height = common->fmt.fmt.pix.height;
+
+ return 0;
+
+invalid_fmt_exit:
+ vpif_err("invalid field format\n");
+ return -EINVAL;
+
+invalid_pitch_exit:
+ vpif_err("invalid pitch\n");
+ return -EINVAL;
+}
+
+static void vpif_config_addr(struct channel_obj *ch, int muxmode)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (VPIF_CHANNEL3_VIDEO == ch->channel_id) {
+ common->set_addr = ch3_set_videobuf_addr;
+ } else {
+ if (2 == muxmode)
+ common->set_addr = ch2_set_videobuf_addr_yc_nmux;
+ else
+ common->set_addr = ch2_set_videobuf_addr;
+ }
+}
+
+/*
+ * vpif_mmap: It is used to map kernel space buffers into user spaces
+ */
+static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX];
+
+ return videobuf_mmap_mapper(&common->buffer_queue, vma);
+}
+
+/*
+ * vpif_poll: It is used for select/poll system call
+ */
+static unsigned int vpif_poll(struct file *filep, poll_table *wait)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (common->started)
+ return videobuf_poll_stream(filep, &common->buffer_queue, wait);
+
+ return 0;
+}
+
+/*
+ * vpif_open: It creates object of file handle structure and stores it in
+ * private_data member of filepointer
+ */
+static int vpif_open(struct file *filep)
+{
+ struct video_device *vdev = video_devdata(filep);
+ struct channel_obj *ch = NULL;
+ struct vpif_fh *fh = NULL;
+
+ ch = video_get_drvdata(vdev);
+ /* Allocate memory for the file handle object */
+ fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+ if (fh == NULL) {
+ vpif_err("unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+
+ /* store pointer to fh in private_data member of filep */
+ filep->private_data = fh;
+ fh->channel = ch;
+ fh->initialized = 0;
+ if (!ch->initialized) {
+ fh->initialized = 1;
+ ch->initialized = 1;
+ memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+ }
+
+ /* Increment channel usrs counter */
+ atomic_inc(&ch->usrs);
+ /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */
+ fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&ch->prio, &fh->prio);
+
+ return 0;
+}
+
+/*
+ * vpif_release: This function deletes buffer queue, frees the buffers and
+ * the vpif file handle
+ */
+static int vpif_release(struct file *filep)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ /* if this instance is doing IO */
+ if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ /* Reset io_usrs member of channel object */
+ common->io_usrs = 0;
+ /* Disable channel */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+ (2 == common->started)) {
+ enable_channel3(0);
+ channel3_intr_enable(0);
+ }
+ common->started = 0;
+ /* Free buffers allocated */
+ videobuf_queue_cancel(&common->buffer_queue);
+ videobuf_mmap_free(&common->buffer_queue);
+ common->numbuffers =
+ config_params.numbuffers[ch->channel_id];
+ }
+
+ mutex_unlock(&common->lock);
+
+ /* Decrement channel usrs counter */
+ atomic_dec(&ch->usrs);
+ /* If this file handle has initialize encoder device, reset it */
+ if (fh->initialized)
+ ch->initialized = 0;
+
+ /* Close the priority */
+ v4l2_prio_close(&ch->prio, &fh->prio);
+ filep->private_data = NULL;
+ fh->initialized = 0;
+ kfree(fh);
+
+ return 0;
+}
+
+/* functions implementing ioctls */
+
+static int vpif_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpif_config *config = vpif_dev->platform_data;
+
+ cap->version = VPIF_DISPLAY_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, "vpif display", sizeof(cap->driver));
+ strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));
+ strlcpy(cap->card, config->card_name, sizeof(cap->card));
+
+ return 0;
+}
+
+static int vpif_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index != 0) {
+ vpif_err("Invalid format index\n");
+ return -EINVAL;
+ }
+
+ /* Fill in the information about format */
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
+ fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+
+ return 0;
+}
+
+static int vpif_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ /* Check the validity of the buffer type */
+ if (common->fmt.type != fmt->type)
+ return -EINVAL;
+
+ /* Fill in the information about format */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (vpif_get_std_info(ch)) {
+ vpif_err("Error getting the standard info\n");
+ return -EINVAL;
+ }
+
+ *fmt = common->fmt;
+ mutex_unlock(&common->lock);
+ return 0;
+}
+
+static int vpif_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct v4l2_pix_format *pixfmt;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+ || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+
+ /* Check for the priority */
+ ret = v4l2_prio_check(&ch->prio, &fh->prio);
+ if (0 != ret)
+ return ret;
+ fh->initialized = 1;
+ }
+
+ if (common->started) {
+ vpif_dbg(1, debug, "Streaming in progress\n");
+ return -EBUSY;
+ }
+
+ pixfmt = &fmt->fmt.pix;
+ /* Check for valid field format */
+ ret = vpif_check_format(ch, pixfmt);
+ if (ret)
+ return ret;
+
+ /* store the pix format in the channel object */
+ common->fmt.fmt.pix = *pixfmt;
+ /* store the format in the channel object */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ common->fmt = *fmt;
+ mutex_unlock(&common->lock);
+
+ return 0;
+}
+
+static int vpif_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ int ret = 0;
+
+ ret = vpif_check_format(ch, pixfmt);
+ if (ret) {
+ *pixfmt = common->fmt.fmt.pix;
+ pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2;
+ }
+
+ return ret;
+}
+
+static int vpif_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbuf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ enum v4l2_field field;
+ u8 index = 0;
+ int ret = 0;
+
+ /* This file handle has not initialized the channel,
+ It is not allowed to do settings */
+ if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+ || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_err("Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type)
+ return -EINVAL;
+
+ index = VPIF_VIDEO_INDEX;
+
+ common = &ch->common[index];
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (common->fmt.type != reqbuf->type) {
+ ret = -EINVAL;
+ goto reqbuf_exit;
+ }
+
+ if (0 != common->io_usrs) {
+ ret = -EBUSY;
+ goto reqbuf_exit;
+ }
+
+ if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
+ field = V4L2_FIELD_INTERLACED;
+ else
+ field = common->fmt.fmt.pix.field;
+ } else {
+ field = V4L2_VBI_INTERLACED;
+ }
+
+ /* Initialize videobuf queue as per the buffer type */
+ videobuf_queue_dma_contig_init(&common->buffer_queue,
+ &video_qops, NULL,
+ &common->irqlock,
+ reqbuf->type, field,
+ sizeof(struct videobuf_buffer), fh);
+
+ /* Set io allowed member of file handle to TRUE */
+ fh->io_allowed[index] = 1;
+ /* Increment io usrs member of channel object to 1 */
+ common->io_usrs = 1;
+ /* Store type of memory requested in channel object */
+ common->memory = reqbuf->memory;
+ INIT_LIST_HEAD(&common->dma_queue);
+
+ /* Allocate buffers */
+ ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
+
+reqbuf_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *tbuf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (common->fmt.type != tbuf->type)
+ return -EINVAL;
+
+ return videobuf_querybuf(&common->buffer_queue, tbuf);
+}
+
+static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct v4l2_buffer tbuf = *buf;
+ struct videobuf_buffer *buf1;
+ unsigned long addr = 0;
+ unsigned long flags;
+ int ret = 0;
+
+ if (common->fmt.type != tbuf.type)
+ return -EINVAL;
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ if (!(list_empty(&common->dma_queue)) ||
+ (common->cur_frm != common->next_frm) ||
+ !(common->started) ||
+ (common->started && (0 == ch->field_id)))
+ return videobuf_qbuf(&common->buffer_queue, buf);
+
+ /* bufferqueue is empty store buffer address in VPIF registers */
+ mutex_lock(&common->buffer_queue.vb_lock);
+ buf1 = common->buffer_queue.bufs[tbuf.index];
+ if (buf1->memory != tbuf.memory) {
+ vpif_err("invalid buffer type\n");
+ goto qbuf_exit;
+ }
+
+ if ((buf1->state == VIDEOBUF_QUEUED) ||
+ (buf1->state == VIDEOBUF_ACTIVE)) {
+ vpif_err("invalid state\n");
+ goto qbuf_exit;
+ }
+
+ switch (buf1->memory) {
+ case V4L2_MEMORY_MMAP:
+ if (buf1->baddr == 0)
+ goto qbuf_exit;
+ break;
+
+ case V4L2_MEMORY_USERPTR:
+ if (tbuf.length < buf1->bsize)
+ goto qbuf_exit;
+
+ if ((VIDEOBUF_NEEDS_INIT != buf1->state)
+ && (buf1->baddr != tbuf.m.userptr))
+ vpif_buffer_release(&common->buffer_queue, buf1);
+ buf1->baddr = tbuf.m.userptr;
+ break;
+
+ default:
+ goto qbuf_exit;
+ }
+
+ local_irq_save(flags);
+ ret = vpif_buffer_prepare(&common->buffer_queue, buf1,
+ common->buffer_queue.field);
+ if (ret < 0) {
+ local_irq_restore(flags);
+ goto qbuf_exit;
+ }
+
+ buf1->state = VIDEOBUF_ACTIVE;
+ addr = buf1->boff;
+ common->next_frm = buf1;
+ if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+ common->set_addr((addr + common->ytop_off),
+ (addr + common->ybtm_off),
+ (addr + common->ctop_off),
+ (addr + common->cbtm_off));
+ }
+
+ local_irq_restore(flags);
+ list_add_tail(&buf1->stream, &common->buffer_queue.stream);
+ mutex_unlock(&common->buffer_queue.vb_lock);
+ return 0;
+
+qbuf_exit:
+ mutex_unlock(&common->buffer_queue.vb_lock);
+ return -EINVAL;
+}
+
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (!(*std_id & DM646X_V4L2_STD))
+ return -EINVAL;
+
+ if (common->started) {
+ vpif_err("streaming in progress\n");
+ return -EBUSY;
+ }
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.stdid = *std_id;
+ /* Get the information about the standard */
+ if (vpif_get_std_info(ch)) {
+ vpif_err("Error getting the standard info\n");
+ return -EINVAL;
+ }
+
+ if ((ch->vpifparams.std_info.width *
+ ch->vpifparams.std_info.height * 2) >
+ config_params.channel_bufsize[ch->channel_id]) {
+ vpif_err("invalid std for this size\n");
+ ret = -EINVAL;
+ goto s_std_exit;
+ }
+
+ common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+ s_std_output, *std_id);
+ if (ret < 0) {
+ vpif_err("Failed to set output standard\n");
+ goto s_std_exit;
+ }
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
+ s_std, *std_id);
+ if (ret < 0)
+ vpif_err("Failed to set standard for sub devices\n");
+
+s_std_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ *std = ch->video.stdid;
+ return 0;
+}
+
+static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ return videobuf_dqbuf(&common->buffer_queue, p,
+ (file->f_flags & O_NONBLOCK));
+}
+
+static int vpif_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
+ struct vpif_params *vpif = &ch->vpifparams;
+ struct vpif_config *vpif_config_data =
+ vpif_dev->platform_data;
+ unsigned long addr = 0;
+ int ret = 0;
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ vpif_err("buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ /* If Streaming is already started, return error */
+ if (common->started) {
+ vpif_err("channel->started\n");
+ return -EBUSY;
+ }
+
+ if ((ch->channel_id == VPIF_CHANNEL2_VIDEO
+ && oth_ch->common[VPIF_VIDEO_INDEX].started &&
+ ch->vpifparams.std_info.ycmux_mode == 0)
+ || ((ch->channel_id == VPIF_CHANNEL3_VIDEO)
+ && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
+ vpif_err("other channel is using\n");
+ return -EBUSY;
+ }
+
+ ret = vpif_check_format(ch, &common->fmt.fmt.pix);
+ if (ret < 0)
+ return ret;
+
+ /* Call videobuf_streamon to start streaming in videobuf */
+ ret = videobuf_streamon(&common->buffer_queue);
+ if (ret < 0) {
+ vpif_err("videobuf_streamon\n");
+ return ret;
+ }
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ /* If buffer queue is empty, return error */
+ if (list_empty(&common->dma_queue)) {
+ vpif_err("buffer queue is empty\n");
+ ret = -EIO;
+ goto streamon_exit;
+ }
+
+ /* Get the next frame from the buffer queue */
+ common->next_frm = common->cur_frm =
+ list_entry(common->dma_queue.next,
+ struct videobuf_buffer, queue);
+
+ list_del(&common->cur_frm->queue);
+ /* Mark state of the current frame to active */
+ common->cur_frm->state = VIDEOBUF_ACTIVE;
+
+ /* Initialize field_id and started member */
+ ch->field_id = 0;
+ common->started = 1;
+ if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ addr = common->cur_frm->boff;
+ /* Calculate the offset for Y and C data in the buffer */
+ vpif_calculate_offsets(ch);
+
+ if ((ch->vpifparams.std_info.frm_fmt &&
+ ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
+ && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
+ || (!ch->vpifparams.std_info.frm_fmt
+ && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
+ vpif_err("conflict in field format and std format\n");
+ ret = -EINVAL;
+ goto streamon_exit;
+ }
+
+ /* clock settings */
+ ret =
+ vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,
+ ch->vpifparams.std_info.hd_sd);
+ if (ret < 0) {
+ vpif_err("can't set clock\n");
+ goto streamon_exit;
+ }
+
+ /* set the parameters and addresses */
+ ret = vpif_set_video_params(vpif, ch->channel_id + 2);
+ if (ret < 0)
+ goto streamon_exit;
+
+ common->started = ret;
+ vpif_config_addr(ch, ret);
+ common->set_addr((addr + common->ytop_off),
+ (addr + common->ybtm_off),
+ (addr + common->ctop_off),
+ (addr + common->cbtm_off));
+
+ /* Set interrupt for both the fields in VPIF
+ Register enable channel in VPIF register */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ channel2_intr_assert();
+ channel2_intr_enable(1);
+ enable_channel2(1);
+ }
+
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
+ || (common->started == 2)) {
+ channel3_intr_assert();
+ channel3_intr_enable(1);
+ enable_channel3(1);
+ }
+ channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
+ }
+
+streamon_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ vpif_err("buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ if (!common->started) {
+ vpif_err("channel->started\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ /* disable channel */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+ (2 == common->started)) {
+ enable_channel3(0);
+ channel3_intr_enable(0);
+ }
+ }
+
+ common->started = 0;
+ mutex_unlock(&common->lock);
+
+ return videobuf_streamoff(&common->buffer_queue);
+}
+
+static int vpif_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type)
+ return -EINVAL;
+
+ crop->bounds.left = crop->bounds.top = 0;
+ crop->defrect.left = crop->defrect.top = 0;
+ crop->defrect.height = crop->bounds.height = common->height;
+ crop->defrect.width = crop->bounds.width = common->width;
+
+ return 0;
+}
+
+static int vpif_enum_output(struct file *file, void *fh,
+ struct v4l2_output *output)
+{
+
+ struct vpif_config *config = vpif_dev->platform_data;
+
+ if (output->index >= config->output_count) {
+ vpif_dbg(1, debug, "Invalid output index\n");
+ return -EINVAL;
+ }
+
+ strcpy(output->name, config->output[output->index]);
+ output->type = V4L2_OUTPUT_TYPE_ANALOG;
+ output->std = DM646X_V4L2_STD;
+
+ return 0;
+}
+
+static int vpif_s_output(struct file *file, void *priv, unsigned int i)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (common->started) {
+ vpif_err("Streaming in progress\n");
+ ret = -EBUSY;
+ goto s_output_exit;
+ }
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+ s_routing, 0, i, 0);
+
+ if (ret < 0)
+ vpif_err("Failed to set output standard\n");
+
+ vid_ch->output_id = i;
+
+s_output_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_g_output(struct file *file, void *priv, unsigned int *i)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ *i = vid_ch->output_id;
+
+ return 0;
+}
+
+static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ *p = v4l2_prio_max(&ch->prio);
+
+ return 0;
+}
+
+static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_prio_change(&ch->prio, &fh->prio, p);
+}
+
+/* vpif display ioctl operations */
+static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
+ .vidioc_querycap = vpif_querycap,
+ .vidioc_g_priority = vpif_g_priority,
+ .vidioc_s_priority = vpif_s_priority,
+ .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,
+ .vidioc_reqbufs = vpif_reqbufs,
+ .vidioc_querybuf = vpif_querybuf,
+ .vidioc_qbuf = vpif_qbuf,
+ .vidioc_dqbuf = vpif_dqbuf,
+ .vidioc_streamon = vpif_streamon,
+ .vidioc_streamoff = vpif_streamoff,
+ .vidioc_s_std = vpif_s_std,
+ .vidioc_g_std = vpif_g_std,
+ .vidioc_enum_output = vpif_enum_output,
+ .vidioc_s_output = vpif_s_output,
+ .vidioc_g_output = vpif_g_output,
+ .vidioc_cropcap = vpif_cropcap,
+};
+
+static const struct v4l2_file_operations vpif_fops = {
+ .owner = THIS_MODULE,
+ .open = vpif_open,
+ .release = vpif_release,
+ .ioctl = video_ioctl2,
+ .mmap = vpif_mmap,
+ .poll = vpif_poll
+};
+
+static struct video_device vpif_video_template = {
+ .name = "vpif",
+ .fops = &vpif_fops,
+ .minor = -1,
+ .ioctl_ops = &vpif_ioctl_ops,
+ .tvnorms = DM646X_V4L2_STD,
+ .current_norm = V4L2_STD_625_50,
+
+};
+
+/*Configure the channels, buffer sizei, request irq */
+static int initialize_vpif(void)
+{
+ int free_channel_objects_index;
+ int free_buffer_channel_index;
+ int free_buffer_index;
+ int err = 0, i, j;
+
+ /* Default number of buffers should be 3 */
+ if ((ch2_numbuffers > 0) &&
+ (ch2_numbuffers < config_params.min_numbuffers))
+ ch2_numbuffers = config_params.min_numbuffers;
+ if ((ch3_numbuffers > 0) &&
+ (ch3_numbuffers < config_params.min_numbuffers))
+ ch3_numbuffers = config_params.min_numbuffers;
+
+ /* Set buffer size to min buffers size if invalid buffer size is
+ * given */
+ if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO])
+ ch2_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL2_VIDEO];
+ if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO])
+ ch3_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL3_VIDEO];
+
+ config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers;
+
+ if (ch2_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] =
+ ch2_bufsize;
+ }
+ config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers;
+
+ if (ch3_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] =
+ ch3_bufsize;
+ }
+
+ /* Allocate memory for six channel objects */
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ vpif_obj.dev[i] =
+ kmalloc(sizeof(struct channel_obj), GFP_KERNEL);
+ /* If memory allocation fails, return error */
+ if (!vpif_obj.dev[i]) {
+ free_channel_objects_index = i;
+ err = -ENOMEM;
+ goto vpif_init_free_channel_objects;
+ }
+ }
+
+ free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES;
+ free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS;
+ free_buffer_index = config_params.numbuffers[i - 1];
+
+ return 0;
+
+vpif_init_free_channel_objects:
+ for (j = 0; j < free_channel_objects_index; j++)
+ kfree(vpif_obj.dev[j]);
+ return err;
+}
+
+/*
+ * vpif_probe: This function creates device entries by register itself to the
+ * V4L2 driver and initializes fields of each channel objects
+ */
+static __init int vpif_probe(struct platform_device *pdev)
+{
+ const struct vpif_subdev_info *subdevdata;
+ int i, j = 0, k, q, m, err = 0;
+ struct i2c_adapter *i2c_adap;
+ struct vpif_config *config;
+ struct common_obj *common;
+ struct channel_obj *ch;
+ struct video_device *vfd;
+ struct resource *res;
+ int subdev_count;
+
+ vpif_dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ v4l2_err(vpif_dev->driver,
+ "Error getting platform resource\n");
+ return -ENOENT;
+ }
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ vpif_dev->driver->name)) {
+ v4l2_err(vpif_dev->driver, "VPIF: failed request_mem_region\n");
+ return -ENXIO;
+ }
+
+ vpif_base = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (!vpif_base) {
+ v4l2_err(vpif_dev->driver, "Unable to ioremap VPIF reg\n");
+ err = -ENXIO;
+ goto resource_exit;
+ }
+
+ vpif_base_addr_init(vpif_base);
+
+ initialize_vpif();
+
+ err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
+ if (err) {
+ v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
+ return err;
+ }
+
+ k = 0;
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {
+ for (i = res->start; i <= res->end; i++) {
+ if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,
+ "DM646x_Display",
+ (void *)(&vpif_obj.dev[k]->channel_id))) {
+ err = -EBUSY;
+ goto vpif_int_err;
+ }
+ }
+ k++;
+ }
+
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+
+ /* Allocate memory for video device */
+ vfd = video_device_alloc();
+ if (vfd == NULL) {
+ for (j = 0; j < i; j++) {
+ ch = vpif_obj.dev[j];
+ video_device_release(ch->video_dev);
+ }
+ err = -ENOMEM;
+ goto video_dev_alloc_exit;
+ }
+
+ /* Initialize field of video device */
+ *vfd = vpif_video_template;
+ vfd->v4l2_dev = &vpif_obj.v4l2_dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d",
+ (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff,
+ (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff,
+ (VPIF_DISPLAY_VERSION_CODE) & 0xff);
+
+ /* Set video_dev to the video device */
+ ch->video_dev = vfd;
+ }
+
+ for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
+ ch = vpif_obj.dev[j];
+ /* Initialize field of the channel objects */
+ atomic_set(&ch->usrs, 0);
+ for (k = 0; k < VPIF_NUMOBJECTS; k++) {
+ ch->common[k].numbuffers = 0;
+ common = &ch->common[k];
+ common->io_usrs = 0;
+ common->started = 0;
+ spin_lock_init(&common->irqlock);
+ mutex_init(&common->lock);
+ common->numbuffers = 0;
+ common->set_addr = NULL;
+ common->ytop_off = common->ybtm_off = 0;
+ common->ctop_off = common->cbtm_off = 0;
+ common->cur_frm = common->next_frm = NULL;
+ memset(&common->fmt, 0, sizeof(common->fmt));
+ common->numbuffers = config_params.numbuffers[k];
+
+ }
+ ch->initialized = 0;
+ ch->channel_id = j;
+ if (j < 2)
+ ch->common[VPIF_VIDEO_INDEX].numbuffers =
+ config_params.numbuffers[ch->channel_id];
+ else
+ ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
+
+ memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+
+ /* Initialize prio member of channel object */
+ v4l2_prio_init(&ch->prio);
+ ch->common[VPIF_VIDEO_INDEX].fmt.type =
+ V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ /* register video device */
+ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
+ (int)ch, (int)&ch->video_dev);
+
+ err = video_register_device(ch->video_dev,
+ VFL_TYPE_GRABBER, (j ? 3 : 2));
+ if (err < 0)
+ goto probe_out;
+
+ video_set_drvdata(ch->video_dev, ch);
+ }
+
+ i2c_adap = i2c_get_adapter(1);
+ config = pdev->dev.platform_data;
+ subdev_count = config->subdev_count;
+ subdevdata = config->subdevinfo;
+ vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+ GFP_KERNEL);
+ if (vpif_obj.sd == NULL) {
+ vpif_err("unable to allocate memory for subdevice pointers\n");
+ err = -ENOMEM;
+ goto probe_out;
+ }
+
+ for (i = 0; i < subdev_count; i++) {
+ vpif_obj.sd[i] = v4l2_i2c_new_probed_subdev(&vpif_obj.v4l2_dev,
+ i2c_adap, subdevdata[i].name,
+ subdevdata[i].name,
+ &subdevdata[i].addr);
+ if (!vpif_obj.sd[i]) {
+ vpif_err("Error registering v4l2 subdevice\n");
+ goto probe_subdev_out;
+ }
+
+ if (vpif_obj.sd[i])
+ vpif_obj.sd[i]->grp_id = 1 << i;
+ }
+
+ return 0;
+
+probe_subdev_out:
+ kfree(vpif_obj.sd);
+probe_out:
+ for (k = 0; k < j; k++) {
+ ch = vpif_obj.dev[k];
+ video_unregister_device(ch->video_dev);
+ video_device_release(ch->video_dev);
+ ch->video_dev = NULL;
+ }
+vpif_int_err:
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+ vpif_err("VPIF IRQ request failed\n");
+ for (q = k; k >= 0; k--) {
+ for (m = i; m >= res->start; m--)
+ free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
+ m = res->end;
+ }
+video_dev_alloc_exit:
+ iounmap(vpif_base);
+resource_exit:
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ return err;
+}
+
+/*
+ * vpif_remove: It un-register channels from V4L2 driver
+ */
+static int vpif_remove(struct platform_device *device)
+{
+ struct channel_obj *ch;
+ int i;
+
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+
+ /* un-register device */
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ /* Unregister video device */
+ video_unregister_device(ch->video_dev);
+
+ ch->video_dev = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver vpif_driver = {
+ .driver = {
+ .name = "vpif_display",
+ .owner = THIS_MODULE,
+ },
+ .probe = vpif_probe,
+ .remove = vpif_remove,
+};
+
+static __init int vpif_init(void)
+{
+ return platform_driver_register(&vpif_driver);
+}
+
+/*
+ * vpif_cleanup: This function un-registers device and driver to the kernel,
+ * frees requested irq handler and de-allocates memory allocated for channel
+ * objects.
+ */
+static void vpif_cleanup(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ int irq_num;
+ int i = 0;
+
+ pdev = container_of(vpif_dev, struct platform_device, dev);
+
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++)
+ free_irq(irq_num,
+ (void *)(&vpif_obj.dev[i]->channel_id));
+ i++;
+ }
+
+ iounmap(vpif_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+ platform_driver_unregister(&vpif_driver);
+ kfree(vpif_obj.sd);
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)
+ kfree(vpif_obj.dev[i]);
+}
+
+module_init(vpif_init);
+module_exit(vpif_cleanup);
diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h
new file mode 100644
index 000000000000..a2a7cd166bbf
--- /dev/null
+++ b/drivers/media/video/davinci/vpif_display.h
@@ -0,0 +1,175 @@
+/*
+ * DM646x display header file
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DAVINCIHD_DISPLAY_H
+#define DAVINCIHD_DISPLAY_H
+
+/* Header files */
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "vpif.h"
+
+/* Macros */
+#define VPIF_MAJOR_RELEASE (0)
+#define VPIF_MINOR_RELEASE (0)
+#define VPIF_BUILD (1)
+
+#define VPIF_DISPLAY_VERSION_CODE \
+ ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
+
+#define VPIF_VALID_FIELD(field) \
+ (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \
+ (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \
+ (V4L2_FIELD_SEQ_BT == field)))
+
+#define VPIF_DISPLAY_MAX_DEVICES (2)
+#define VPIF_SLICED_BUF_SIZE (256)
+#define VPIF_SLICED_MAX_SERVICES (3)
+#define VPIF_VIDEO_INDEX (0)
+#define VPIF_VBI_INDEX (1)
+#define VPIF_HBI_INDEX (2)
+
+/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/
+#define VPIF_NUMOBJECTS (1)
+
+/* Macros */
+#define ISALIGNED(a) (0 == ((a) & 7))
+
+/* enumerated data types */
+/* Enumerated data type to give id to each device per channel */
+enum vpif_channel_id {
+ VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */
+ VPIF_CHANNEL3_VIDEO, /* Channel3 Video */
+};
+
+/* structures */
+
+struct video_obj {
+ enum v4l2_field buf_field;
+ u32 latest_only; /* indicate whether to return
+ * most recent displayed frame only */
+ v4l2_std_id stdid; /* Currently selected or default
+ * standard */
+ u32 output_id; /* Current output id */
+};
+
+struct vbi_obj {
+ int num_services;
+ struct vpif_vbi_params vbiparams; /* vpif parameters for the raw
+ * vbi data */
+};
+
+struct common_obj {
+ /* Buffer specific parameters */
+ u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for
+ * storing frames */
+ u32 numbuffers; /* number of buffers */
+ struct videobuf_buffer *cur_frm; /* Pointer pointing to current
+ * videobuf_buffer */
+ struct videobuf_buffer *next_frm; /* Pointer pointing to next
+ * videobuf_buffer */
+ enum v4l2_memory memory; /* This field keeps track of
+ * type of buffer exchange
+ * method user has selected */
+ struct v4l2_format fmt; /* Used to store the format */
+ struct videobuf_queue buffer_queue; /* Buffer queue used in
+ * video-buf */
+ struct list_head dma_queue; /* Queue of filled frames */
+ spinlock_t irqlock; /* Used in video-buf */
+
+ /* channel specific parameters */
+ struct mutex lock; /* lock used to access this
+ * structure */
+ u32 io_usrs; /* number of users performing
+ * IO */
+ u8 started; /* Indicates whether streaming
+ * started */
+ u32 ytop_off; /* offset of Y top from the
+ * starting of the buffer */
+ u32 ybtm_off; /* offset of Y bottom from the
+ * starting of the buffer */
+ u32 ctop_off; /* offset of C top from the
+ * starting of the buffer */
+ u32 cbtm_off; /* offset of C bottom from the
+ * starting of the buffer */
+ /* Function pointer to set the addresses */
+ void (*set_addr) (unsigned long, unsigned long,
+ unsigned long, unsigned long);
+ u32 height;
+ u32 width;
+};
+
+struct channel_obj {
+ /* V4l2 specific parameters */
+ struct video_device *video_dev; /* Identifies video device for
+ * this channel */
+ struct v4l2_prio_state prio; /* Used to keep track of state of
+ * the priority */
+ atomic_t usrs; /* number of open instances of
+ * the channel */
+ u32 field_id; /* Indicates id of the field
+ * which is being displayed */
+ u8 initialized; /* flag to indicate whether
+ * encoder is initialized */
+
+ enum vpif_channel_id channel_id;/* Identifies channel */
+ struct vpif_params vpifparams;
+ struct common_obj common[VPIF_NUMOBJECTS];
+ struct video_obj video;
+ struct vbi_obj vbi;
+};
+
+/* File handle structure */
+struct vpif_fh {
+ struct channel_obj *channel; /* pointer to channel object for
+ * opened device */
+ u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle
+ * is doing IO */
+ enum v4l2_priority prio; /* Used to keep track priority of
+ * this instance */
+ u8 initialized; /* Used to keep track of whether this
+ * file handle has initialized
+ * channel or not */
+};
+
+/* vpif device structure */
+struct vpif_device {
+ struct v4l2_device v4l2_dev;
+ struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS];
+ struct v4l2_subdev **sd;
+
+};
+
+struct vpif_config_params {
+ u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
+ u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
+ u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS];
+ u8 min_numbuffers;
+};
+
+/* Struct which keeps track of the line numbers for the sliced vbi service */
+struct vpif_service_line {
+ u16 service_id;
+ u16 service_line[2];
+ u16 enc_service_id;
+ u8 bytestowrite;
+};
+
+#endif /* DAVINCIHD_DISPLAY_H */
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c
new file mode 100644
index 000000000000..6d709ca8cfb0
--- /dev/null
+++ b/drivers/media/video/davinci/vpss.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * 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.
+ *
+ * common vpss driver for all video drivers.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <media/davinci/vpss.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VPSS Driver");
+MODULE_AUTHOR("Texas Instruments");
+
+/* DM644x defines */
+#define DM644X_SBL_PCR_VPSS (4)
+
+/* vpss BL register offsets */
+#define DM355_VPSSBL_CCDCMUX 0x1c
+/* vpss CLK register offsets */
+#define DM355_VPSSCLK_CLKCTRL 0x04
+/* masks and shifts */
+#define VPSS_HSSISEL_SHIFT 4
+
+/*
+ * vpss operations. Depends on platform. Not all functions are available
+ * on all platforms. The api, first check if a functio is available before
+ * invoking it. In the probe, the function ptrs are intialized based on
+ * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
+ */
+struct vpss_hw_ops {
+ /* enable clock */
+ int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
+ /* select input to ccdc */
+ void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
+ /* clear wbl overlflow bit */
+ int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
+};
+
+/* vpss configuration */
+struct vpss_oper_config {
+ __iomem void *vpss_bl_regs_base;
+ __iomem void *vpss_regs_base;
+ struct resource *r1;
+ resource_size_t len1;
+ struct resource *r2;
+ resource_size_t len2;
+ char vpss_name[32];
+ spinlock_t vpss_lock;
+ struct vpss_hw_ops hw_ops;
+};
+
+static struct vpss_oper_config oper_cfg;
+
+/* register access routines */
+static inline u32 bl_regr(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_bl_regs_base + offset);
+}
+
+static inline void bl_regw(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_bl_regs_base + offset);
+}
+
+static inline u32 vpss_regr(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_regs_base + offset);
+}
+
+static inline void vpss_regw(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_regs_base + offset);
+}
+
+static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
+}
+
+int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ if (!oper_cfg.hw_ops.select_ccdc_source)
+ return -1;
+
+ dm355_select_ccdc_source(src_sel);
+ return 0;
+}
+EXPORT_SYMBOL(vpss_select_ccdc_source);
+
+static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+ u32 mask = 1, val;
+
+ if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
+ wbl_sel > VPSS_PCR_CCDC_WBL_O)
+ return -1;
+
+ /* writing a 0 clear the overflow */
+ mask = ~(mask << wbl_sel);
+ val = bl_regr(DM644X_SBL_PCR_VPSS) & mask;
+ bl_regw(val, DM644X_SBL_PCR_VPSS);
+ return 0;
+}
+
+int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+ if (!oper_cfg.hw_ops.clear_wbl_overflow)
+ return -1;
+
+ return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
+}
+EXPORT_SYMBOL(vpss_clear_wbl_overflow);
+
+/*
+ * dm355_enable_clock - Enable VPSS Clock
+ * @clock_sel: CLock to be enabled/disabled
+ * @en: enable/disable flag
+ *
+ * This is called to enable or disable a vpss clock
+ */
+static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ unsigned long flags;
+ u32 utemp, mask = 0x1, shift = 0;
+
+ switch (clock_sel) {
+ case VPSS_VPBE_CLOCK:
+ /* nothing since lsb */
+ break;
+ case VPSS_VENC_CLOCK_SEL:
+ shift = 2;
+ break;
+ case VPSS_CFALD_CLOCK:
+ shift = 3;
+ break;
+ case VPSS_H3A_CLOCK:
+ shift = 4;
+ break;
+ case VPSS_IPIPE_CLOCK:
+ shift = 5;
+ break;
+ case VPSS_CCDC_CLOCK:
+ shift = 6;
+ break;
+ default:
+ printk(KERN_ERR "dm355_enable_clock:"
+ " Invalid selector: %d\n", clock_sel);
+ return -1;
+ }
+
+ spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
+ utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL);
+ if (!en)
+ utemp &= ~(mask << shift);
+ else
+ utemp |= (mask << shift);
+
+ vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL);
+ spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
+ return 0;
+}
+
+int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ if (!oper_cfg.hw_ops.enable_clock)
+ return -1;
+
+ return oper_cfg.hw_ops.enable_clock(clock_sel, en);
+}
+EXPORT_SYMBOL(vpss_enable_clock);
+
+static int __init vpss_probe(struct platform_device *pdev)
+{
+ int status, dm355 = 0;
+
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENOENT;
+ }
+ strcpy(oper_cfg.vpss_name, pdev->dev.platform_data);
+
+ if (!strcmp(oper_cfg.vpss_name, "dm355_vpss"))
+ dm355 = 1;
+ else if (strcmp(oper_cfg.vpss_name, "dm644x_vpss")) {
+ dev_err(&pdev->dev, "vpss driver not supported on"
+ " this platform\n");
+ return -ENODEV;
+ }
+
+ dev_info(&pdev->dev, "%s vpss probed\n", oper_cfg.vpss_name);
+ oper_cfg.r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!oper_cfg.r1)
+ return -ENOENT;
+
+ oper_cfg.len1 = oper_cfg.r1->end - oper_cfg.r1->start + 1;
+
+ oper_cfg.r1 = request_mem_region(oper_cfg.r1->start, oper_cfg.len1,
+ oper_cfg.r1->name);
+ if (!oper_cfg.r1)
+ return -EBUSY;
+
+ oper_cfg.vpss_bl_regs_base = ioremap(oper_cfg.r1->start, oper_cfg.len1);
+ if (!oper_cfg.vpss_bl_regs_base) {
+ status = -EBUSY;
+ goto fail1;
+ }
+
+ if (dm355) {
+ oper_cfg.r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!oper_cfg.r2) {
+ status = -ENOENT;
+ goto fail2;
+ }
+ oper_cfg.len2 = oper_cfg.r2->end - oper_cfg.r2->start + 1;
+ oper_cfg.r2 = request_mem_region(oper_cfg.r2->start,
+ oper_cfg.len2,
+ oper_cfg.r2->name);
+ if (!oper_cfg.r2) {
+ status = -EBUSY;
+ goto fail2;
+ }
+
+ oper_cfg.vpss_regs_base = ioremap(oper_cfg.r2->start,
+ oper_cfg.len2);
+ if (!oper_cfg.vpss_regs_base) {
+ status = -EBUSY;
+ goto fail3;
+ }
+ }
+
+ if (dm355) {
+ oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
+ oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
+ } else
+ oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
+
+ spin_lock_init(&oper_cfg.vpss_lock);
+ dev_info(&pdev->dev, "%s vpss probe success\n", oper_cfg.vpss_name);
+ return 0;
+
+fail3:
+ release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
+fail2:
+ iounmap(oper_cfg.vpss_bl_regs_base);
+fail1:
+ release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
+ return status;
+}
+
+static int vpss_remove(struct platform_device *pdev)
+{
+ iounmap(oper_cfg.vpss_bl_regs_base);
+ release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
+ if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) {
+ iounmap(oper_cfg.vpss_regs_base);
+ release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
+ }
+ return 0;
+}
+
+static struct platform_driver vpss_driver = {
+ .driver = {
+ .name = "vpss",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(vpss_remove),
+ .probe = vpss_probe,
+};
+
+static void vpss_exit(void)
+{
+ platform_driver_unregister(&vpss_driver);
+}
+
+static int __init vpss_init(void)
+{
+ return platform_driver_register(&vpss_driver);
+}
+subsys_initcall(vpss_init);
+module_exit(vpss_exit);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 1c2e544eda73..b184d482c497 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -558,6 +558,27 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+ [EM2861_BOARD_GADMEI_UTV330PLUS] = {
+ .name = "Gadmei UTV330+",
+ .tuner_type = TUNER_TNF_5335MF,
+ .tda9887_conf = TDA9887_PRESENT,
+ .ir_codes = ir_codes_gadmei_rm008z,
+ .decoder = EM28XX_SAA711X,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = SAA7115_COMPOSITE2,
+ .amux = EM28XX_AMUX_VIDEO,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
[EM2860_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Cinergy A Hybrid XS",
.valid = EM28XX_BOARD_NOT_VALIDATED,
@@ -870,6 +891,8 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_TVP5150,
.has_dvb = 1,
.dvb_gpio = default_digital,
+ .ir_codes = ir_codes_terratec_cinergy_xs,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -1649,6 +1672,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
{ USB_DEVICE(0x04bb, 0x0515),
.driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
+ { USB_DEVICE(0xeb1a, 0x50a6),
+ .driver_info = EM2860_BOARD_GADMEI_UTV330 },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -1661,7 +1686,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
{0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
{0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
- {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
+ {0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
{0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
{0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
};
@@ -1672,6 +1697,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
{0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
{0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
+ {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
};
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 27e33a287dfc..71474d31e155 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -459,7 +459,6 @@ static struct i2c_algorithm em28xx_algo = {
static struct i2c_adapter em28xx_adap_template = {
.owner = THIS_MODULE,
.name = "em28xx",
- .id = I2C_HW_B_EM28XX,
.algo = &em28xx_algo,
};
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index ab079d9256c4..a6bdbc21410e 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -124,7 +124,7 @@ static struct em28xx_fmt format[] = {
/* supported controls */
/* Common to all boards */
-static struct v4l2_queryctrl em28xx_qctrl[] = {
+static struct v4l2_queryctrl ac97_qctrl[] = {
{
.id = V4L2_CID_AUDIO_VOLUME,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -133,7 +133,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
.maximum = 0x1f,
.step = 0x1,
.default_value = 0x1f,
- .flags = 0,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_AUDIO_MUTE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -609,10 +609,29 @@ static void res_free(struct em28xx_fh *fh)
}
/*
- * em28xx_get_ctrl()
- * return the current saturation, brightness or contrast, mute state
+ * ac97_queryctrl()
+ * return the ac97 supported controls
*/
-static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+static int ac97_queryctrl(struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+ if (qc->id && qc->id == ac97_qctrl[i].id) {
+ memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+
+ /* Control is not ac97 related */
+ return 1;
+}
+
+/*
+ * ac97_get_ctrl()
+ * return the current values for ac97 mute and volume
+ */
+static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
@@ -622,29 +641,41 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
ctrl->value = dev->volume;
return 0;
default:
- return -EINVAL;
+ /* Control is not ac97 related */
+ return 1;
}
}
/*
- * em28xx_set_ctrl()
- * mute or set new saturation, brightness or contrast
+ * ac97_set_ctrl()
+ * set values for ac97 mute and volume
*/
-static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
+ if (ctrl->id == ac97_qctrl[i].id)
+ goto handle;
+
+ /* Announce that hasn't handle it */
+ return 1;
+
+handle:
+ if (ctrl->value < ac97_qctrl[i].minimum ||
+ ctrl->value > ac97_qctrl[i].maximum)
+ return -ERANGE;
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value != dev->mute) {
- dev->mute = ctrl->value;
- return em28xx_audio_analog_set(dev);
- }
- return 0;
+ dev->mute = ctrl->value;
+ break;
case V4L2_CID_AUDIO_VOLUME:
dev->volume = ctrl->value;
- return em28xx_audio_analog_set(dev);
- default:
- return -EINVAL;
+ break;
}
+
+ return em28xx_audio_analog_set(dev);
}
static int check_dev(struct em28xx *dev)
@@ -974,6 +1005,9 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
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");
@@ -1015,6 +1049,9 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
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)
@@ -1038,7 +1075,6 @@ static int vidioc_queryctrl(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int id = qc->id;
- int i;
int rc;
rc = check_dev(dev);
@@ -1049,15 +1085,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
qc->id = id;
- if (!dev->board.has_msp34xx) {
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (qc->id && qc->id == em28xx_qctrl[i].id) {
- memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
+ /* enumberate AC97 controls */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ rc = ac97_queryctrl(qc);
+ if (!rc)
+ return 0;
}
+ /* enumberate V4L2 device controls */
mutex_lock(&dev->lock);
v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
mutex_unlock(&dev->lock);
@@ -1082,14 +1117,16 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
mutex_lock(&dev->lock);
- if (dev->board.has_msp34xx)
+ /* Set an AC97 control */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+ rc = ac97_get_ctrl(dev, ctrl);
+ else
+ rc = 1;
+
+ /* It were not an AC97 control. Sends it to the v4l2 dev interface */
+ if (rc == 1) {
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
- else {
- rc = em28xx_get_ctrl(dev, ctrl);
- if (rc < 0) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
- rc = 0;
- }
+ rc = 0;
}
mutex_unlock(&dev->lock);
@@ -1101,7 +1138,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u8 i;
int rc;
rc = check_dev(dev);
@@ -1110,28 +1146,31 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
mutex_lock(&dev->lock);
- if (dev->board.has_msp34xx)
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
- else {
+ /* Set an AC97 control */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+ rc = ac97_set_ctrl(dev, ctrl);
+ else
rc = 1;
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (ctrl->id == em28xx_qctrl[i].id) {
- if (ctrl->value < em28xx_qctrl[i].minimum ||
- ctrl->value > em28xx_qctrl[i].maximum) {
- rc = -ERANGE;
- break;
- }
-
- rc = em28xx_set_ctrl(dev, ctrl);
- break;
- }
- }
- }
- /* Control not found - try to send it to the attached devices */
+ /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
if (rc == 1) {
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
- rc = 0;
+
+ /*
+ * In the case of non-AC97 volume controls, we still need
+ * to do some setups at em28xx, in order to mute/unmute
+ * and to adjust audio volume. However, the value ranges
+ * should be checked by the corresponding V4L subdriver.
+ */
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ dev->mute = ctrl->value;
+ rc = em28xx_audio_analog_set(dev);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->volume = ctrl->value;
+ rc = em28xx_audio_analog_set(dev);
+ }
}
mutex_unlock(&dev->lock);
@@ -1275,8 +1314,9 @@ static int vidioc_g_register(struct file *file, void *priv,
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
return 0;
case V4L2_CHIP_MATCH_I2C_ADDR:
- /* Not supported yet */
- return -EINVAL;
+ /* TODO: is this correct? */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+ return 0;
default:
if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
@@ -1327,8 +1367,9 @@ static int vidioc_s_register(struct file *file, void *priv,
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
return 0;
case V4L2_CHIP_MATCH_I2C_ADDR:
- /* Not supported yet */
- return -EINVAL;
+ /* TODO: is this correct? */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+ return 0;
default:
if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
@@ -1431,9 +1472,11 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities =
V4L2_CAP_SLICED_VBI_CAPTURE |
V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (dev->audio_mode.has_audio)
+ cap->capabilities |= V4L2_CAP_AUDIO;
+
if (dev->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER;
@@ -1654,9 +1697,9 @@ static int radio_queryctrl(struct file *file, void *priv,
qc->id >= V4L2_CID_LASTP1)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (qc->id && qc->id == em28xx_qctrl[i].id) {
- memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+ if (qc->id && qc->id == ac97_qctrl[i].id) {
+ memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
return 0;
}
}
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index a2add61f7d59..23f34dd691e9 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -108,6 +108,7 @@
#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
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index e994dcac43ff..8897283b0bb4 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -47,6 +47,15 @@ config USB_GSPCA_FINEPIX
To compile this driver as a module, choose M here: the
module will be called gspca_finepix.
+config USB_GSPCA_JEILINJ
+ tristate "Jeilin JPEG USB V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on this Jeilin chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_jeilinj.
+
config USB_GSPCA_MARS
tristate "Mars USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -103,9 +112,9 @@ config USB_GSPCA_PAC7311
module will be called gspca_pac7311.
config USB_GSPCA_SN9C20X
- tristate "SN9C20X USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
+ tristate "SN9C20X USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
Say Y here if you want support for cameras based on the
sn9c20x chips (SN9C201 and SN9C202).
@@ -113,10 +122,10 @@ config USB_GSPCA_SN9C20X
module will be called gspca_sn9c20x.
config USB_GSPCA_SN9C20X_EVDEV
- bool "Enable evdev support"
+ bool "Enable evdev support"
depends on USB_GSPCA_SN9C20X && INPUT
- ---help---
- Say Y here in order to enable evdev support for sn9c20x webcam button.
+ ---help---
+ Say Y here in order to enable evdev support for sn9c20x webcam button.
config USB_GSPCA_SONIXB
tristate "SONIX Bayer USB Camera Driver"
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index f6d3b86e9ad5..035616b5e867 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o
obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
+obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o
@@ -30,6 +31,7 @@ gspca_main-objs := gspca.o
gspca_conex-objs := conex.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
+gspca_jeilinj-objs := jeilinj.o
gspca_mars-objs := mars.o
gspca_mr97310a-objs := mr97310a.o
gspca_ov519-objs := ov519.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index 8d48ea1742c2..eca003566ae3 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -820,7 +820,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index 2c20d06a03e8..c1461e63647f 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -635,10 +635,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = id->driver_info;
if (sd->sensor == SENSOR_PAS106) {
cam->cam_mode = sif_mode;
- cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ cam->nmodes = ARRAY_SIZE(sif_mode);
} else {
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
gspca_dev->ctrl_dis = (1 << COLOR_IDX);
}
sd->brightness = BRIGHTNESS_DEF;
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index b8561dfb6c8c..cf6540da1e42 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -47,7 +47,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 6, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 7, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -486,6 +486,7 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
}
PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
i, ep->desc.bEndpointAddress);
+ gspca_dev->alt = i; /* memorize the current alt setting */
if (gspca_dev->nbalt > 1) {
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
if (ret < 0) {
@@ -493,7 +494,6 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
return NULL;
}
}
- gspca_dev->alt = i; /* memorize the current alt setting */
return ep;
}
@@ -512,7 +512,10 @@ static int create_urbs(struct gspca_dev *gspca_dev,
if (!gspca_dev->cam.bulk) { /* isoc */
/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
- psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ if (gspca_dev->pkt_size == 0)
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ else
+ psize = gspca_dev->pkt_size;
npkt = gspca_dev->cam.npkt;
if (npkt == 0)
npkt = 32; /* default value */
@@ -597,13 +600,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* set the higher alternate setting and
* loop until urb submit succeeds */
gspca_dev->alt = gspca_dev->nbalt;
+ if (gspca_dev->sd_desc->isoc_init) {
+ ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
+ if (ret < 0)
+ goto out;
+ }
+ ep = get_ep(gspca_dev);
+ if (ep == NULL) {
+ ret = -EIO;
+ goto out;
+ }
for (;;) {
PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
- ep = get_ep(gspca_dev);
- if (ep == NULL) {
- ret = -EIO;
- goto out;
- }
ret = create_urbs(gspca_dev, ep);
if (ret < 0)
goto out;
@@ -628,21 +636,32 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* submit the URBs */
for (n = 0; n < gspca_dev->nurbs; n++) {
ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
- if (ret < 0) {
- PDEBUG(D_ERR|D_STREAM,
- "usb_submit_urb [%d] err %d", n, ret);
- gspca_dev->streaming = 0;
- destroy_urbs(gspca_dev);
- if (ret == -ENOSPC) {
- msleep(20); /* wait for kill
- * complete */
- break; /* try the previous alt */
- }
- goto out;
- }
+ if (ret < 0)
+ break;
}
if (ret >= 0)
break;
+ PDEBUG(D_ERR|D_STREAM,
+ "usb_submit_urb alt %d err %d", gspca_dev->alt, ret);
+ gspca_dev->streaming = 0;
+ destroy_urbs(gspca_dev);
+ if (ret != -ENOSPC)
+ goto out;
+
+ /* the bandwidth is not wide enough
+ * negociate or try a lower alternate setting */
+ msleep(20); /* wait for kill complete */
+ if (gspca_dev->sd_desc->isoc_nego) {
+ ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
+ if (ret < 0)
+ goto out;
+ } else {
+ ep = get_ep(gspca_dev);
+ if (ep == NULL) {
+ ret = -EIO;
+ goto out;
+ }
+ }
}
out:
mutex_unlock(&gspca_dev->usb_lock);
@@ -1473,12 +1492,6 @@ static int vidioc_s_parm(struct file *filp, void *priv,
return 0;
}
-static int vidioc_s_std(struct file *filp, void *priv,
- v4l2_std_id *parm)
-{
- return 0;
-}
-
#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf(struct file *file, void *priv,
struct video_mbuf *mbuf)
@@ -1949,7 +1962,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
- .vidioc_s_std = vidioc_s_std,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 46c4effdfcd5..70b1fd830876 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -98,9 +98,11 @@ struct sd_desc {
/* mandatory operations */
cam_cf_op config; /* called on probe */
cam_op init; /* called on probe and resume */
- cam_op start; /* called on stream on */
+ cam_op start; /* called on stream on after URBs creation */
cam_pkt_op pkt_scan;
/* optional operations */
+ cam_op isoc_init; /* called on stream on before getting the EP */
+ cam_op isoc_nego; /* called when URB submit failed with NOSPC */
cam_v_op stopN; /* called on stream off - main alt */
cam_v_op stop0; /* called on stream off & disconnect - alt 0 */
cam_v_op dq_callback; /* called when a frame has been dequeued */
@@ -178,6 +180,7 @@ struct gspca_dev {
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
__u8 nbalt; /* number of USB alternate settings */
+ u16 pkt_size; /* ISOC packet size */
};
int gspca_dev_probe(struct usb_interface *intf,
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
new file mode 100644
index 000000000000..dbfa3ed6e8ef
--- /dev/null
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -0,0 +1,388 @@
+/*
+ * Jeilinj subdriver
+ *
+ * Supports some Jeilin dual-mode cameras which use bulk transport and
+ * download raw JPEG data.
+ *
+ * Copyright (C) 2009 Theodore Kilgore
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "jeilinj"
+
+#include <linux/workqueue.h>
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define JEILINJ_CMD_TIMEOUT 500
+#define JEILINJ_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define JEILINJ_MAX_TRANSFER 0x200
+
+#define FRAME_HEADER_LEN 0x10
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ const struct v4l2_pix_format *cap_mode;
+ /* Driver stuff */
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
+ u8 quality; /* image quality */
+ u8 jpegqual; /* webcam quality */
+ u8 *jpeg_hdr;
+};
+
+ struct jlj_command {
+ unsigned char instruction[2];
+ unsigned char ack_wanted;
+ };
+
+/* AFAICT these cameras will only do 320x240. */
+static struct v4l2_pix_format jlj_mode[] = {
+ { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0}
+};
+
+/*
+ * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
+ * and 0x82 for bulk transfer.
+ */
+
+/* All commands are two bytes only */
+static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+{
+ int retval;
+
+ memcpy(gspca_dev->usb_buf, command, 2);
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_sndbulkpipe(gspca_dev->dev, 3),
+ gspca_dev->usb_buf, 2, NULL, 500);
+ if (retval < 0)
+ PDEBUG(D_ERR, "command write [%02x] error %d",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+/* Responses are one byte only */
+static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
+{
+ int retval;
+
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x84),
+ gspca_dev->usb_buf, 1, NULL, 500);
+ response = gspca_dev->usb_buf[0];
+ if (retval < 0)
+ PDEBUG(D_ERR, "read command [%02x] error %d",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+static int jlj_start(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ u8 response = 0xff;
+ struct jlj_command start_commands[] = {
+ {{0x71, 0x81}, 0},
+ {{0x70, 0x05}, 0},
+ {{0x95, 0x70}, 1},
+ {{0x71, 0x81}, 0},
+ {{0x70, 0x04}, 0},
+ {{0x95, 0x70}, 1},
+ {{0x71, 0x00}, 0},
+ {{0x70, 0x08}, 0},
+ {{0x95, 0x70}, 1},
+ {{0x94, 0x02}, 0},
+ {{0xde, 0x24}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xdd, 0xf0}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe3, 0x2c}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe4, 0x00}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe5, 0x00}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe6, 0x2c}, 0},
+ {{0x94, 0x03}, 0},
+ {{0xaa, 0x00}, 0},
+ {{0x71, 0x1e}, 0},
+ {{0x70, 0x06}, 0},
+ {{0x71, 0x80}, 0},
+ {{0x70, 0x07}, 0}
+ };
+ for (i = 0; i < ARRAY_SIZE(start_commands); i++) {
+ retval = jlj_write2(gspca_dev, start_commands[i].instruction);
+ if (retval < 0)
+ return retval;
+ if (start_commands[i].ack_wanted)
+ retval = jlj_read1(gspca_dev, response);
+ if (retval < 0)
+ return retval;
+ }
+ PDEBUG(D_ERR, "jlj_start retval is %d", retval);
+ return retval;
+}
+
+static int jlj_stop(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval;
+ struct jlj_command stop_commands[] = {
+ {{0x71, 0x00}, 0},
+ {{0x70, 0x09}, 0},
+ {{0x71, 0x80}, 0},
+ {{0x70, 0x05}, 0}
+ };
+ for (i = 0; i < ARRAY_SIZE(stop_commands); i++) {
+ retval = jlj_write2(gspca_dev, stop_commands[i].instruction);
+ if (retval < 0)
+ return retval;
+ }
+ return retval;
+}
+
+/* This function is called as a workqueue function and runs whenever the camera
+ * is streaming data. Because it is a workqueue function it is allowed to sleep
+ * so we can use synchronous USB calls. To avoid possible collisions with other
+ * threads attempting to use the camera's USB interface the gspca usb_lock is
+ * used when performing the one USB control operation inside the workqueue,
+ * which tells the camera to close the stream. In practice the only thing
+ * which needs to be protected against is the usb_set_interface call that
+ * gspca makes during stream_off. Otherwise the camera doesn't provide any
+ * controls that the user could try to change.
+ */
+
+static void jlj_dostream(struct work_struct *work)
+{
+ struct sd *dev = container_of(work, struct sd, work_struct);
+ struct gspca_dev *gspca_dev = &dev->gspca_dev;
+ struct gspca_frame *frame;
+ int blocks_left; /* 0x200-sized blocks remaining in current frame. */
+ int size_in_blocks;
+ int act_len;
+ int discarding = 0; /* true if we failed to get space for frame. */
+ int packet_type;
+ int ret;
+ u8 *buffer;
+
+ buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+ goto quit_stream;
+ }
+ while (gspca_dev->present && gspca_dev->streaming) {
+ if (!gspca_dev->present)
+ goto quit_stream;
+ /* Start a new frame, and add the JPEG header, first thing */
+ frame = gspca_get_i_frame(gspca_dev);
+ if (frame && !discarding)
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ dev->jpeg_hdr, JPEG_HDR_SZ);
+ else
+ discarding = 1;
+ /*
+ * Now request data block 0. Line 0 reports the size
+ * to download, in blocks of size 0x200, and also tells the
+ * "actual" data size, in bytes, which seems best to ignore.
+ */
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, JEILINJ_MAX_TRANSFER, &act_len,
+ JEILINJ_DATA_TIMEOUT);
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for Block 0",
+ act_len, JEILINJ_MAX_TRANSFER);
+ if (ret < 0 || act_len < FRAME_HEADER_LEN)
+ goto quit_stream;
+ size_in_blocks = buffer[0x0a];
+ blocks_left = buffer[0x0a] - 1;
+ PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
+ packet_type = INTER_PACKET;
+ if (frame && !discarding)
+ /* Toss line 0 of data block 0, keep the rest. */
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer + FRAME_HEADER_LEN,
+ JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
+ else
+ discarding = 1;
+ while (blocks_left > 0) {
+ if (!gspca_dev->present)
+ goto quit_stream;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, JEILINJ_MAX_TRANSFER, &act_len,
+ JEILINJ_DATA_TIMEOUT);
+ if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER)
+ goto quit_stream;
+ PDEBUG(D_STREAM,
+ "%d blocks remaining for frame", blocks_left);
+ blocks_left -= 1;
+ if (blocks_left == 0)
+ packet_type = LAST_PACKET;
+ else
+ packet_type = INTER_PACKET;
+ if (frame && !discarding)
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer,
+ JEILINJ_MAX_TRANSFER);
+ else
+ discarding = 1;
+ }
+ }
+quit_stream:
+ mutex_lock(&gspca_dev->usb_lock);
+ if (gspca_dev->present)
+ jlj_stop(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ kfree(buffer);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct cam *cam = &gspca_dev->cam;
+ struct sd *dev = (struct sd *) gspca_dev;
+
+ dev->quality = 85;
+ dev->jpegqual = 85;
+ PDEBUG(D_PROBE,
+ "JEILINJ camera detected"
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ cam->cam_mode = jlj_mode;
+ cam->nmodes = 1;
+ cam->bulk = 1;
+ /* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk_size = 32;
+ INIT_WORK(&dev->work_struct, jlj_dostream);
+ return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+
+ /* wait for the work queue to terminate */
+ mutex_unlock(&gspca_dev->usb_lock);
+ /* This waits for jlj_dostream to finish */
+ destroy_workqueue(dev->work_thread);
+ dev->work_thread = NULL;
+ mutex_lock(&gspca_dev->usb_lock);
+ kfree(dev->jpeg_hdr);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+ int ret;
+
+ /* create the JPEG header */
+ dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(dev->jpeg_hdr, dev->quality);
+ PDEBUG(D_STREAM, "Start streaming at 320x240");
+ ret = jlj_start(gspca_dev);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Start streaming command failed");
+ return ret;
+ }
+ /* Start the workqueue function to do the streaming */
+ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
+ queue_work(dev->work_thread, &dev->work_struct);
+
+ return 0;
+}
+
+/* Table of supported USB devices */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0979, 0x0280)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id,
+ &sd_desc,
+ sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index 7127321ace8c..6b89f33a4ce0 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -178,8 +178,10 @@ sensor_found:
sens_priv->settings =
kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
- if (!sens_priv->settings)
+ 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);
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index e1e3a3a50484..0caf3c075730 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -1068,6 +1068,7 @@ static __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
+ {USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
{}
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index fcfbbd329b4c..52a7f8edf7ac 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -1096,12 +1096,12 @@ int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
reg_r(gspca_dev, 0x10c0, 1);
if (gspca_dev->usb_buf[0] & 0x04) {
if (gspca_dev->usb_buf[0] & 0x08)
- return -1;
+ return -EIO;
return 0;
}
msleep(1);
}
- return -1;
+ return -EIO;
}
int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
@@ -1152,7 +1152,7 @@ int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
- row[0] = 0x81 | 0x10;
+ row[0] = 0x81 | (1 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
row[3] = 0;
@@ -1160,14 +1160,15 @@ int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- reg_w(gspca_dev, 0x10c0, row, 8);
- msleep(1);
- row[0] = 0x81 | (2 << 4) | 0x02;
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ row[0] = 0x81 | (1 << 4) | 0x02;
row[2] = 0;
- reg_w(gspca_dev, 0x10c0, row, 8);
- msleep(1);
- reg_r(gspca_dev, 0x10c2, 5);
- *val = gspca_dev->usb_buf[3];
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ if (reg_r(gspca_dev, 0x10c2, 5) < 0)
+ return -EIO;
+ *val = gspca_dev->usb_buf[4];
return 0;
}
@@ -1176,7 +1177,7 @@ int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
- row[0] = 0x81 | 0x10;
+ row[0] = 0x81 | (1 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
row[3] = 0;
@@ -1184,14 +1185,15 @@ int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- reg_w(gspca_dev, 0x10c0, row, 8);
- msleep(1);
- row[0] = 0x81 | (3 << 4) | 0x02;
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ row[0] = 0x81 | (2 << 4) | 0x02;
row[2] = 0;
- reg_w(gspca_dev, 0x10c0, row, 8);
- msleep(1);
- reg_r(gspca_dev, 0x10c2, 5);
- *val = (gspca_dev->usb_buf[2] << 8) | gspca_dev->usb_buf[3];
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ if (reg_r(gspca_dev, 0x10c2, 5) < 0)
+ return -EIO;
+ *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
return 0;
}
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index d6332ab80669..f0b762f770fb 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -727,13 +727,13 @@ static const u8 ov7660_sensor_init[][8] = {
{0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
/* Outformat = rawRGB */
{0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
- {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
+ {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
/* GAIN BLUE RED VREF */
{0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
/* COM 1 BAVE GEAVE AECHH */
{0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
{0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
- {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
+ {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
/* AECH CLKRC COM7 COM8 */
{0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
{0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
@@ -1637,16 +1637,19 @@ static void setfreq(struct gspca_dev *gspca_dev)
if (gspca_dev->ctrl_dis & (1 << FREQ_IDX))
return;
if (sd->sensor == SENSOR_OV7660) {
+ u8 com8;
+
+ com8 = 0xf8; /* no auto gain/wb/expo */
switch (sd->freq) {
case 0: /* Banding filter disabled */
- i2c_w1(gspca_dev, 0x13, 0xdf);
+ i2c_w1(gspca_dev, 0x13, com8 & 0xdf);
break;
case 1: /* 50 hz */
- i2c_w1(gspca_dev, 0x13, 0xff);
+ i2c_w1(gspca_dev, 0x13, com8);
i2c_w1(gspca_dev, 0x3b, 0x0a);
break;
case 2: /* 60 hz */
- i2c_w1(gspca_dev, 0x13, 0xff);
+ i2c_w1(gspca_dev, 0x13, com8);
i2c_w1(gspca_dev, 0x3b, 0x02);
break;
}
@@ -2336,7 +2339,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
#endif
{USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
-/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
+/* {USB_DEVICE(0x0c45, 0x6102), BSI(SN9C120, PO2030N, ??)}, */
+/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6802, 0x21)}, */
{USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
{USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
{USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
@@ -2352,6 +2356,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
#endif
+/* {USB_DEVICE(0x0c45, 0x6132), BSI(SN9C120, OV7670, 0x21)}, */
{USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
{USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
@@ -2359,7 +2364,9 @@ static const __devinitdata struct usb_device_id device_table[] = {
#endif
{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
{USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)},
- {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
+/* {USB_DEVICE(0x0c45, 0x6142), BSI(SN9C120, PO2030N, ??)}, *sn9c120b*/
+ {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, /*sn9c120b*/
+ {USB_DEVICE(0x0c45, 0x6148), BSI(SN9C120, OM6802, 0x21)}, /*sn9c120b*/
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index d48b27c648ca..b74a34218da0 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -1923,7 +1923,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
sd->subtype = id->driver_info;
sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
index 3a0c893f942d..a199298a6419 100644
--- a/drivers/media/video/gspca/spca506.c
+++ b/drivers/media/video/gspca/spca506.c
@@ -286,7 +286,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 2ed2669bac3e..9696c4caf5c9 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1304,19 +1304,70 @@ static int reg_read(struct gspca_dev *gspca_dev,
return gspca_dev->usb_buf[0];
}
+/* send 1 or 2 bytes to the sensor via the Synchronous Serial Interface */
+static int ssi_w(struct gspca_dev *gspca_dev,
+ u16 reg, u16 val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, retry;
+
+ ret = reg_write(dev, 0x8802, reg >> 8);
+ if (ret < 0)
+ goto out;
+ ret = reg_write(dev, 0x8801, reg & 0x00ff);
+ if (ret < 0)
+ goto out;
+ if ((reg & 0xff00) == 0x1000) { /* if 2 bytes */
+ ret = reg_write(dev, 0x8805, val & 0x00ff);
+ if (ret < 0)
+ goto out;
+ val >>= 8;
+ }
+ ret = reg_write(dev, 0x8800, val);
+ if (ret < 0)
+ goto out;
+
+ /* poll until not busy */
+ retry = 10;
+ for (;;) {
+ ret = reg_read(gspca_dev, 0x8803);
+ if (ret < 0)
+ break;
+ if (gspca_dev->usb_buf[0] == 0)
+ break;
+ if (--retry <= 0) {
+ PDEBUG(D_ERR, "ssi_w busy %02x",
+ gspca_dev->usb_buf[0]);
+ ret = -1;
+ break;
+ }
+ msleep(8);
+ }
+
+out:
+ return ret;
+}
+
static int write_vector(struct gspca_dev *gspca_dev,
const u16 (*data)[2])
{
struct usb_device *dev = gspca_dev->dev;
- int ret;
+ int ret = 0;
while ((*data)[1] != 0) {
- ret = reg_write(dev, (*data)[1], (*data)[0]);
+ if ((*data)[1] & 0x8000) {
+ if ((*data)[1] == 0xdd00) /* delay */
+ msleep((*data)[0]);
+ else
+ ret = reg_write(dev, (*data)[1], (*data)[0]);
+ } else {
+ ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]);
+ }
if (ret < 0)
- return ret;
+ break;
data++;
}
- return 0;
+ return ret;
}
/* this function is called at probe time */
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 0da8e0de0456..7af511b5e9c2 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -130,8 +130,8 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
STV06XX_URB_MSG_TIMEOUT);
if (err < 0)
return err;
- }
- return stv06xx_write_sensor_finish(sd);
+ }
+ return stv06xx_write_sensor_finish(sd);
}
int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 5127bbf9dd26..e9481fa77749 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -52,6 +52,7 @@ struct sd {
#define LogitechClickSmart420 2
#define LogitechClickSmart820 3
#define MegapixV4 4
+#define MegaImageVI 5
u8 *jpeg_hdr;
};
@@ -840,15 +841,18 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* case BRIDGE_SPCA504: */
/* case BRIDGE_SPCA536: */
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes =ARRAY_SIZE(vga_mode);
break;
case BRIDGE_SPCA533:
cam->cam_mode = custom_mode;
- cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+ if (sd->subtype == MegaImageVI) /* 320x240 only */
+ cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
+ else
+ cam->nmodes = ARRAY_SIZE(custom_mode);
break;
case BRIDGE_SPCA504C:
cam->cam_mode = vga_mode2;
- cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode2);
break;
}
sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
@@ -988,7 +992,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA536: */
if (sd->subtype == MegapixV4 ||
- sd->subtype == LogitechClickSmart820) {
+ sd->subtype == LogitechClickSmart820 ||
+ sd->subtype == MegaImageVI) {
reg_w(gspca_dev, 0xf0, 0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
reg_r(gspca_dev, 0xf0, 4, 0);
@@ -1384,6 +1389,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
{USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
{USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
+ {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
{USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
{USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
{USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 404214b8cd2b..1d321c30d22f 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -264,6 +264,10 @@ static const struct v4l2_pix_format vga_mode_t16[] = {
/* sensor specific data */
struct additional_sensor_data {
+ const u8 n3[6];
+ const u8 *n4, n4sz;
+ const u8 reg80, reg8e;
+ const u8 nset8[6];
const u8 data1[10];
const u8 data2[9];
const u8 data3[9];
@@ -272,14 +276,55 @@ struct additional_sensor_data {
const u8 stream[4];
};
+static const u8 n4_om6802[] = {
+ 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+ 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+ 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+ 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+ 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+ 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+ 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+ 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+ 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
+};
+static const u8 n4_other[] = {
+ 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
+ 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
+ 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
+ 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
+ 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
+ 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
+ 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
+ 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
+};
+static const u8 n4_tas5130a[] = {
+ 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
+ 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
+ 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
+ 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
+ 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
+ 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
+ 0xc6, 0xda
+};
+
static const struct additional_sensor_data sensor_data[] = {
- { /* OM6802 */
+ { /* 0: OM6802 */
+ .n3 =
+ {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
+ .n4 = n4_om6802,
+ .n4sz = sizeof n4_om6802,
+ .reg80 = 0x3c,
+ .reg8e = 0x33,
+ .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
.data1 =
{0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
0xb3, 0xfc},
.data2 =
{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
0xff},
+ .data3 =
+ {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
+ 0xff},
.data4 = /*Freq (50/60Hz). Splitted for test purpose */
{0x66, 0xca, 0xa8, 0xf0},
.data5 = /* this could be removed later */
@@ -287,13 +332,23 @@ static const struct additional_sensor_data sensor_data[] = {
.stream =
{0x0b, 0x04, 0x0a, 0x78},
},
- { /* OTHER */
+ { /* 1: OTHER */
+ .n3 =
+ {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
+ .n4 = n4_other,
+ .n4sz = sizeof n4_other,
+ .reg80 = 0xac,
+ .reg8e = 0xb8,
+ .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
.data1 =
{0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
0xe8, 0xfc},
.data2 =
{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
0xd9},
+ .data3 =
+ {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
+ 0xd9},
.data4 =
{0x66, 0x00, 0xa8, 0xa8},
.data5 =
@@ -301,13 +356,23 @@ static const struct additional_sensor_data sensor_data[] = {
.stream =
{0x0b, 0x04, 0x0a, 0x00},
},
- { /* TAS5130A */
+ { /* 2: TAS5130A */
+ .n3 =
+ {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
+ .n4 = n4_tas5130a,
+ .n4sz = sizeof n4_tas5130a,
+ .reg80 = 0x3c,
+ .reg8e = 0xb4,
+ .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
.data1 =
{0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
0xc8, 0xfc},
.data2 =
{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
0xe0},
+ .data3 =
+ {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
+ 0xe0},
.data4 = /* Freq (50/60Hz). Splitted for test purpose */
{0x66, 0x00, 0xa8, 0xe8},
.data5 =
@@ -364,7 +429,7 @@ static const u8 gamma_table[GAMMA_MAX][17] = {
{0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e, /* 10 */
0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
0xff},
- {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8D, 0x9B, /* 11 */
+ {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b, /* 11 */
0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
0xff},
{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
@@ -385,8 +450,6 @@ static const u8 tas5130a_sensor_init[][8] = {
{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
- {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
- {},
};
static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
@@ -633,10 +696,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
* but wont hurt anyway, and can help someone with similar webcam
* to see the initial parameters.*/
struct sd *sd = (struct sd *) gspca_dev;
+ const struct additional_sensor_data *sensor;
int i;
u16 sensor_id;
u8 test_byte = 0;
- u16 reg80, reg8e;
static const u8 read_indexs[] =
{ 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
@@ -645,37 +708,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
static const u8 n2[] =
{0x08, 0x00};
- static const u8 n3[6] =
- {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
- static const u8 n3_other[6] =
- {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00};
- static const u8 n4[] =
- {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
- 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
- 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
- 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
- 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
- 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
- 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
- 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
- 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
- static const u8 n4_other[] =
- {0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
- 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
- 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
- 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
- 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
- 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
- 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
- 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00};
- static const u8 nset8[6] =
- { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
- static const u8 nset8_other[6] =
- { 0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00 };
- static const u8 nset9[4] =
- { 0x0b, 0x04, 0x0a, 0x78 };
- static const u8 nset9_other[4] =
- { 0x0b, 0x04, 0x0a, 0x00 };
sensor_id = (reg_r(gspca_dev, 0x06) << 8)
| reg_r(gspca_dev, 0x07);
@@ -709,8 +741,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
}
if (i < 0) {
err("Bad sensor reset %02x", test_byte);
-/* return -EIO; */
-/*fixme: test - continue */
+ return -EIO;
}
reg_w_buf(gspca_dev, n2, sizeof n2);
}
@@ -723,31 +754,17 @@ static int sd_init(struct gspca_dev *gspca_dev)
i++;
}
- if (sd->sensor != SENSOR_OTHER) {
- reg_w_buf(gspca_dev, n3, sizeof n3);
- reg_w_buf(gspca_dev, n4, sizeof n4);
- reg_r(gspca_dev, 0x0080);
- reg_w(gspca_dev, 0x2c80);
- reg80 = 0x3880;
- reg8e = 0x338e;
- } else {
- reg_w_buf(gspca_dev, n3_other, sizeof n3_other);
- reg_w_buf(gspca_dev, n4_other, sizeof n4_other);
- sd->gamma = 5;
- reg80 = 0xac80;
- reg8e = 0xb88e;
- }
+ sensor = &sensor_data[sd->sensor];
+ reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
+ reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
- reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
- sizeof sensor_data[sd->sensor].data1);
- reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
- reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
+ reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
+ reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
+ reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
- reg_w(gspca_dev, reg80);
- reg_w(gspca_dev, reg80);
- reg_w(gspca_dev, reg8e);
+ reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
+ reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
+ reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
setbrightness(gspca_dev);
setcontrast(gspca_dev);
@@ -760,25 +777,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x2088);
reg_w(gspca_dev, 0x2089);
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
- sizeof sensor_data[sd->sensor].data4);
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
- sizeof sensor_data[sd->sensor].data5);
- if (sd->sensor != SENSOR_OTHER) {
- reg_w_buf(gspca_dev, nset8, sizeof nset8);
- reg_w_buf(gspca_dev, nset9, sizeof nset9);
- reg_w(gspca_dev, 0x2880);
- } else {
- reg_w_buf(gspca_dev, nset8_other, sizeof nset8_other);
- reg_w_buf(gspca_dev, nset9_other, sizeof nset9_other);
- }
+ reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
+ reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
+ reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
+ reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
- reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
- sizeof sensor_data[sd->sensor].data1);
- reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
- reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
+ reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
+ reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
+ reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
return 0;
}
@@ -828,7 +834,6 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
* i added some module parameters for test with some users */
static void poll_sensor(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
static const u8 poll1[] =
{0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
@@ -844,24 +849,23 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
0xc2, 0x80, 0xc3, 0x10};
- if (sd->sensor == SENSOR_OM6802) {
- PDEBUG(D_STREAM, "[Sensor requires polling]");
- reg_w_buf(gspca_dev, poll1, sizeof poll1);
- reg_w_buf(gspca_dev, poll2, sizeof poll2);
- reg_w_buf(gspca_dev, poll3, sizeof poll3);
- reg_w_buf(gspca_dev, poll4, sizeof poll4);
- }
+ PDEBUG(D_STREAM, "[Sensor requires polling]");
+ reg_w_buf(gspca_dev, poll1, sizeof poll1);
+ reg_w_buf(gspca_dev, poll2, sizeof poll2);
+ reg_w_buf(gspca_dev, poll3, sizeof poll3);
+ reg_w_buf(gspca_dev, poll4, sizeof poll4);
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ const struct additional_sensor_data *sensor;
int i, mode;
u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
static const u8 t3[] =
{ 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (mode) {
case 0: /* 640x480 (0x00) */
break;
@@ -889,34 +893,33 @@ static int sd_start(struct gspca_dev *gspca_dev)
default:
/* case SENSOR_TAS5130A: */
i = 0;
- while (tas5130a_sensor_init[i][0] != 0) {
+ for (;;) {
reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
sizeof tas5130a_sensor_init[0]);
+ if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
+ break;
i++;
}
reg_w(gspca_dev, 0x3c80);
/* just in case and to keep sync with logs (for mine) */
- reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
+ reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
sizeof tas5130a_sensor_init[0]);
reg_w(gspca_dev, 0x3c80);
break;
}
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
- sizeof sensor_data[sd->sensor].data4);
+ sensor = &sensor_data[sd->sensor];
+ reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
reg_r(gspca_dev, 0x0012);
reg_w_buf(gspca_dev, t2, sizeof t2);
reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
reg_w(gspca_dev, 0x0013);
msleep(15);
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
- sizeof sensor_data[sd->sensor].stream);
- poll_sensor(gspca_dev);
+ reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
+ reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
+
+ if (sd->sensor == SENSOR_OM6802)
+ poll_sensor(gspca_dev);
- /* restart on each start, just in case, sometimes regs goes wrong
- * when using controls from app */
- setbrightness(gspca_dev);
- setcontrast(gspca_dev);
- setcolors(gspca_dev);
return 0;
}
@@ -926,10 +929,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
sizeof sensor_data[sd->sensor].stream);
- msleep(20);
reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
sizeof sensor_data[sd->sensor].stream);
- if (sd->sensor != SENSOR_OTHER) {
+ if (sd->sensor == SENSOR_OM6802) {
msleep(20);
reg_w(gspca_dev, 0x0309);
}
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index 9f243d7e3110..4b44dde9f8b8 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -426,7 +426,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, packet_type0,
frame, data + 2, gspca_dev->width);
gspca_frame_add(gspca_dev, packet_type1,
- frame, data + gspca_dev->width + 6, gspca_dev->width);
+ frame, data + gspca_dev->width + 5, gspca_dev->width);
}
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 26dd155efcc3..cdd6c02ce81d 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -32,14 +32,14 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u8 hflip;
- __u8 vflip;
- __u8 lightfreq;
- __u8 sharpness;
+ u8 hflip;
+ u8 vflip;
+ u8 lightfreq;
+ u8 sharpness;
u8 image_offset;
- char bridge;
+ u8 bridge;
#define BRIDGE_VC0321 0
#define BRIDGE_VC0323 1
u8 sensor;
@@ -52,6 +52,10 @@ struct sd {
#define SENSOR_OV7670 6
#define SENSOR_PO1200 7
#define SENSOR_PO3130NC 8
+ u8 flags;
+#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */
+#define FL_HFLIP 0x02 /* mirrored by default */
+#define FL_VFLIP 0x04 /* vertical flipped by default */
};
/* V4L2 controls supported by the driver */
@@ -65,7 +69,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
-/* next 2 controls work with ov7660 and ov7670 only */
+/* next 2 controls work with some sensors only */
#define HFLIP_IDX 0
{
{
@@ -152,9 +156,9 @@ static const struct v4l2_pix_format vc0323_mode[] = {
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
- {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi13x0_soc only */
+ {1280, 960, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */
.bytesperline = 1280,
- .sizeimage = 1280 * 1024 * 1 / 4 + 590,
+ .sizeimage = 1280 * 960 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
};
@@ -188,11 +192,11 @@ static const struct v4l2_pix_format svga_mode[] = {
#define OV7660_MVFP_MIRROR 0x20
#define OV7660_MVFP_VFLIP 0x10
-static const __u8 mi0360_matrix[9] = {
+static const u8 mi0360_matrix[9] = {
0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
};
-static const __u8 mi0360_initVGA_JPG[][4] = {
+static const u8 mi0360_initVGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -301,7 +305,7 @@ static const __u8 mi0360_initVGA_JPG[][4] = {
{0xb3, 0x5c, 0x01, 0xcc},
{}
};
-static const __u8 mi0360_initQVGA_JPG[][4] = {
+static const u8 mi0360_initQVGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -421,211 +425,95 @@ static const __u8 mi0360_initQVGA_JPG[][4] = {
{}
};
-static const __u8 mi1310_socinitVGA_JPG[][4] = {
+static const u8 mi1310_socinitVGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
{0xb3, 0x08, 0x01, 0xcc},
{0xb3, 0x09, 0x0c, 0xcc},
{0xb3, 0x34, 0x02, 0xcc},
{0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
{0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x0d, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
{0xb3, 0x20, 0x00, 0xcc},
{0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
{0xb3, 0x14, 0x00, 0xcc},
{0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x26, 0x80, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb8, 0x00, 0x13, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xb8, 0x81, 0x01, 0xcc},
- {0xb8, 0x2c, 0x5a, 0xcc},
- {0xb8, 0x2d, 0xff, 0xcc},
- {0xb8, 0x2e, 0xee, 0xcc},
- {0xb8, 0x2f, 0xfb, 0xcc},
- {0xb8, 0x30, 0x52, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf1, 0xcc},
- {0xb8, 0x33, 0xff, 0xcc},
- {0xb8, 0x34, 0x54, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x0d, 0x00, 0x09, 0xbb},
- {0x0d, 0x00, 0x08, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
{0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x06, 0x00, 0x14, 0xbb},
- {0x3a, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x9b, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x41, 0x00, 0xd7, 0xbb},
- {0x09, 0x02, 0x3a, 0xbb},
- {0x0c, 0x00, 0x00, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0x05, 0x00, 0x8c, 0xbb},
- {0x06, 0x00, 0x32, 0xbb},
- {0x07, 0x00, 0xc6, 0xbb},
- {0x08, 0x00, 0x19, 0xbb},
- {0x24, 0x80, 0x6f, 0xbb},
- {0xc8, 0x00, 0x0f, 0xbb},
- {0x20, 0x00, 0x0f, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc},
{0xb6, 0x00, 0x00, 0xcc},
{0xb6, 0x03, 0x02, 0xcc},
{0xb6, 0x02, 0x80, 0xcc},
{0xb6, 0x05, 0x01, 0xcc},
{0xb6, 0x04, 0xe0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x25, 0xcc},
{0xb6, 0x18, 0x02, 0xcc},
{0xb6, 0x17, 0x58, 0xcc},
{0xb6, 0x16, 0x00, 0xcc},
{0xb6, 0x22, 0x12, 0xcc},
{0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0x03, 0x03, 0xc0, 0xbb},
- {0x06, 0x00, 0x10, 0xbb},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0x2f, 0x00, 0xC0, 0xbb},
- {0xb8, 0xa0, 0x12, 0xcc},
- {},
-};
-static const __u8 mi1310_socinitQVGA_JPG[][4] = {
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x0d, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x26, 0x80, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb8, 0x00, 0x13, 0xcc},
- {0xbc, 0x00, 0xd1, 0xcc},
- {0xb8, 0x81, 0x01, 0xcc},
- {0xb8, 0x2c, 0x5a, 0xcc},
- {0xb8, 0x2d, 0xff, 0xcc},
- {0xb8, 0x2e, 0xee, 0xcc},
- {0xb8, 0x2f, 0xfb, 0xcc},
- {0xb8, 0x30, 0x52, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf1, 0xcc},
- {0xb8, 0x33, 0xff, 0xcc},
- {0xb8, 0x34, 0x54, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x0d, 0x00, 0x09, 0xbb},
- {0x0d, 0x00, 0x08, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x06, 0x00, 0x14, 0xbb},
- {0x3a, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x9b, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x41, 0x00, 0xd7, 0xbb},
- {0x09, 0x02, 0x3a, 0xbb},
- {0x0c, 0x00, 0x00, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0x05, 0x00, 0x8c, 0xbb},
- {0x06, 0x00, 0x32, 0xbb},
- {0x07, 0x00, 0xc6, 0xbb},
- {0x08, 0x00, 0x19, 0xbb},
- {0x24, 0x80, 0x6f, 0xbb},
- {0xc8, 0x00, 0x0f, 0xbb},
- {0x20, 0x00, 0x0f, 0xbb},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x01, 0xcc},
- {0xb6, 0x02, 0x40, 0xcc},
- {0xb6, 0x05, 0x00, 0xcc},
- {0xb6, 0x04, 0xf0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
- {0xb6, 0x18, 0x00, 0xcc},
- {0xb6, 0x17, 0x96, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
{0xbf, 0xc0, 0x39, 0xcc},
{0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
{0xbc, 0x02, 0x18, 0xcc},
{0xbc, 0x03, 0x50, 0xcc},
{0xbc, 0x04, 0x18, 0xcc},
@@ -636,133 +524,335 @@ static const __u8 mi1310_socinitQVGA_JPG[][4] = {
{0xbc, 0x0a, 0x10, 0xcc},
{0xbc, 0x0b, 0x00, 0xcc},
{0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
{0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+static const u8 mi1310_socinitQVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
{0x03, 0x03, 0xc0, 0xbb},
- {0x06, 0x00, 0x10, 0xbb},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0x2f, 0x00, 0xC0, 0xbb},
- {0xb8, 0xa0, 0x12, 0xcc},
{},
};
static const u8 mi1310_soc_InitSXGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
{0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
{0xb3, 0x08, 0x01, 0xcc},
{0xb3, 0x09, 0x0c, 0xcc},
{0xb3, 0x34, 0x02, 0xcc},
{0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
{0xb3, 0x03, 0x0a, 0xcc},
{0xb3, 0x04, 0x0d, 0xcc},
{0xb3, 0x20, 0x00, 0xcc},
{0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x04, 0xcc},
- {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
{0xb3, 0x14, 0x00, 0xcc},
{0xb3, 0x15, 0x00, 0xcc},
{0xb3, 0x16, 0x04, 0xcc},
{0xb3, 0x17, 0xff, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x26, 0x80, 0xcc},
- {0xb8, 0x06, 0x00, 0xcc},
- {0xb8, 0x07, 0x05, 0xcc},
- {0xb8, 0x08, 0x00, 0xcc},
- {0xb8, 0x09, 0x04, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb8, 0x00, 0x11, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xb8, 0x81, 0x01, 0xcc},
- {0xb8, 0x2c, 0x5a, 0xcc},
- {0xb8, 0x2d, 0xff, 0xcc},
- {0xb8, 0x2e, 0xee, 0xcc},
- {0xb8, 0x2f, 0xfb, 0xcc},
- {0xb8, 0x30, 0x52, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf1, 0xcc},
- {0xb8, 0x33, 0xff, 0xcc},
- {0xb8, 0x34, 0x54, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x70, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x0d, 0x00, 0x09, 0xbb},
- {0x0d, 0x00, 0x08, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
{0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x06, 0x00, 0x14, 0xbb},
- {0x3a, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x9b, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x60, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x37, 0x01, 0x40, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x41, 0x00, 0xd7, 0xbb},
- {0x09, 0x02, 0x3a, 0xbb},
- {0x0c, 0x00, 0x00, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0x05, 0x00, 0x8c, 0xbb},
- {0x06, 0x00, 0x32, 0xbb},
- {0x07, 0x00, 0xc6, 0xbb},
- {0x08, 0x00, 0x19, 0xbb},
- {0x24, 0x80, 0x6f, 0xbb},
- {0xc8, 0x00, 0x0f, 0xbb},
- {0x20, 0x00, 0x03, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
{0xb6, 0x00, 0x00, 0xcc},
{0xb6, 0x03, 0x05, 0xcc},
{0xb6, 0x02, 0x00, 0xcc},
- {0xb6, 0x05, 0x04, 0xcc},
- {0xb6, 0x04, 0x00, 0xcc},
+ {0xb6, 0x05, 0x03, 0xcc},
+ {0xb6, 0x04, 0xc0, 0xcc},
{0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x18, 0x0a, 0xcc},
- {0xb6, 0x17, 0x00, 0xcc},
+ {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x09, 0xcc},
+ {0xb6, 0x17, 0x60, 0xcc},
{0xb6, 0x16, 0x00, 0xcc},
{0xb6, 0x22, 0x12, 0xcc},
{0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
{0xbf, 0xc0, 0x39, 0xcc},
{0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x14, 0xcc},
- {0xb9, 0x14, 0x14, 0xcc},
- {0xb9, 0x15, 0x14, 0xcc},
- {0xb9, 0x16, 0x14, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x1e, 0xcc},
- {0xb9, 0x1a, 0x1e, 0xcc},
- {0xb9, 0x1b, 0x1e, 0xcc},
- {0xb9, 0x1c, 0x1e, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
{0xb3, 0x01, 0x41, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0x2f, 0x00, 0xC0, 0xbb},
- {0xb8, 0xa0, 0x12, 0xcc},
+ {0x00, 0x00, 0x80, 0xdd},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x06, 0xf0, 0x8e, 0xbb},
+ {0x00, 0x00, 0x80, 0xdd},
+ {0x06, 0x70, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5e, 0x6a, 0x53, 0xbb},
+ {0x5f, 0x40, 0x2c, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x58, 0x00, 0x00, 0xbb},
+ {0x53, 0x09, 0x03, 0xbb},
+ {0x54, 0x31, 0x18, 0xbb},
+ {0x55, 0x8b, 0x5f, 0xbb},
+ {0x56, 0xc0, 0xa9, 0xbb},
+ {0x57, 0xe0, 0xd2, 0xbb},
+ {0xe1, 0x00, 0x00, 0xbb},
+ {0xdc, 0x09, 0x03, 0xbb},
+ {0xdd, 0x31, 0x18, 0xbb},
+ {0xde, 0x8b, 0x5f, 0xbb},
+ {0xdf, 0xc0, 0xa9, 0xbb},
+ {0xe0, 0xe0, 0xd2, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf0, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
+ {0xbc, 0x11, 0x03, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
{}
};
-static const __u8 mi1320_gamma[17] = {
+static const u8 mi1320_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 mi1320_matrix[9] = {
+static const u8 mi1320_matrix[9] = {
0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
};
-static const __u8 mi1320_initVGA_data[][4] = {
+static const u8 mi1320_initVGA_data[][4] = {
{0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
@@ -841,7 +931,7 @@ static const __u8 mi1320_initVGA_data[][4] = {
{0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
{}
};
-static const __u8 mi1320_initQVGA_data[][4] = {
+static const u8 mi1320_initQVGA_data[][4] = {
{0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
@@ -948,7 +1038,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
{0x07, 0x00, 0xe0, 0xbb},
{0x08, 0x00, 0x0b, 0xbb},
{0x21, 0x00, 0x0c, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0xbf, 0xc0, 0x26, 0xcc},
{0xbf, 0xc1, 0x02, 0xcc},
{0xbf, 0xcc, 0x04, 0xcc},
@@ -958,7 +1048,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x01, 0x42, 0xbb},
{0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1051,7 +1141,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
{0x07, 0x00, 0xe0, 0xbb},
{0x08, 0x00, 0x0b, 0xbb},
{0x21, 0x00, 0x0c, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0xbf, 0xc0, 0x26, 0xcc},
{0xbf, 0xc1, 0x02, 0xcc},
{0xbf, 0xcc, 0x04, 0xcc},
@@ -1071,7 +1161,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x01, 0x42, 0xbb},
{0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1161,7 +1251,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x00, 0x00, 0x20, 0xdd},
{0xf0, 0x00, 0x00, 0xbb},
{0x00, 0x00, 0x30, 0xdd},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x00, 0x00, 0x20, 0xdd},
{0xbf, 0xc0, 0x26, 0xcc},
{0xbf, 0xc1, 0x02, 0xcc},
@@ -1172,7 +1262,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x01, 0x42, 0xbb},
{0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1230,7 +1320,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x00, 0x85, 0xbb},
{0x08, 0x00, 0x27, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1249,15 +1339,15 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x64, 0x5e, 0x1c, 0xbb},
{}
};
-static const __u8 po3130_gamma[17] = {
+static const u8 po3130_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 po3130_matrix[9] = {
+static const u8 po3130_matrix[9] = {
0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
};
-static const __u8 po3130_initVGA_data[][4] = {
+static const u8 po3130_initVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
@@ -1340,7 +1430,7 @@ static const __u8 po3130_initVGA_data[][4] = {
{0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
{}
};
-static const __u8 po3130_rundata[][4] = {
+static const u8 po3130_rundata[][4] = {
{0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa},
{0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa},
{0x00, 0x44, 0x40, 0xaa},
@@ -1355,7 +1445,7 @@ static const __u8 po3130_rundata[][4] = {
{}
};
-static const __u8 po3130_initQVGA_data[][4] = {
+static const u8 po3130_initQVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc},
{0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
@@ -1441,16 +1531,16 @@ static const __u8 po3130_initQVGA_data[][4] = {
{}
};
-static const __u8 hv7131r_gamma[17] = {
+static const u8 hv7131r_gamma[17] = {
/* 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
* 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
};
-static const __u8 hv7131r_matrix[9] = {
+static const u8 hv7131r_matrix[9] = {
0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
};
-static const __u8 hv7131r_initVGA_data[][4] = {
+static const u8 hv7131r_initVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -1493,7 +1583,7 @@ static const __u8 hv7131r_initVGA_data[][4] = {
{}
};
-static const __u8 hv7131r_initQVGA_data[][4] = {
+static const u8 hv7131r_initQVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -1548,14 +1638,14 @@ static const __u8 hv7131r_initQVGA_data[][4] = {
{}
};
-static const __u8 ov7660_gamma[17] = {
+static const u8 ov7660_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 ov7660_matrix[9] = {
+static const u8 ov7660_matrix[9] = {
0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
};
-static const __u8 ov7660_initVGA_data[][4] = {
+static const u8 ov7660_initVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd},
{0xb0, 0x03, 0x01, 0xcc},
@@ -1613,7 +1703,7 @@ static const __u8 ov7660_initVGA_data[][4] = {
{0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc},
{}
};
-static const __u8 ov7660_initQVGA_data[][4] = {
+static const u8 ov7660_initQVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
@@ -1682,26 +1772,26 @@ static const __u8 ov7660_initQVGA_data[][4] = {
{}
};
-static const __u8 ov7660_50HZ[][4] = {
+static const u8 ov7660_50HZ[][4] = {
{0x00, 0x3b, 0x08, 0xaa},
{0x00, 0x9d, 0x40, 0xaa},
{0x00, 0x13, 0xa7, 0xaa},
{}
};
-static const __u8 ov7660_60HZ[][4] = {
+static const u8 ov7660_60HZ[][4] = {
{0x00, 0x3b, 0x00, 0xaa},
{0x00, 0x9e, 0x40, 0xaa},
{0x00, 0x13, 0xa7, 0xaa},
{}
};
-static const __u8 ov7660_NoFliker[][4] = {
+static const u8 ov7660_NoFliker[][4] = {
{0x00, 0x13, 0x87, 0xaa},
{}
};
-static const __u8 ov7670_initVGA_JPG[][4] = {
+static const u8 ov7670_initVGA_JPG[][4] = {
{0xb3, 0x01, 0x05, 0xcc},
{0x00, 0x00, 0x30, 0xdd}, {0xb0, 0x03, 0x19, 0xcc},
{0x00, 0x00, 0x10, 0xdd},
@@ -1831,7 +1921,7 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
{},
};
-static const __u8 ov7670_initQVGA_JPG[][4] = {
+static const u8 ov7670_initQVGA_JPG[][4] = {
{0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x30, 0xdd},
{0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
{0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
@@ -1966,14 +2056,14 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
};
/* PO1200 - values from usbvm326.inf and ms-win trace */
-static const __u8 po1200_gamma[17] = {
+static const u8 po1200_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 po1200_matrix[9] = {
+static const u8 po1200_matrix[9] = {
0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
};
-static const __u8 po1200_initVGA_data[][4] = {
+static const u8 po1200_initVGA_data[][4] = {
{0xb0, 0x03, 0x19, 0xcc}, /* reset? */
{0xb0, 0x03, 0x19, 0xcc},
/* {0x00, 0x00, 0x33, 0xdd}, */
@@ -2276,9 +2366,9 @@ static const struct sensor_info sensor_info_data[] = {
/* read 'len' bytes in gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
- __u16 req,
- __u16 index,
- __u16 len)
+ u16 req,
+ u16 index,
+ u16 len)
{
usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
@@ -2290,9 +2380,9 @@ static void reg_r(struct gspca_dev *gspca_dev,
}
static void reg_w(struct usb_device *dev,
- __u16 req,
- __u16 value,
- __u16 index)
+ u16 req,
+ u16 value,
+ u16 index)
{
usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -2342,11 +2432,18 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
int i;
u16 value;
const struct sensor_info *ptsensor_info;
+/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
+ if (sd->flags & FL_SAMSUNG) {
+ reg_w(dev, 0xa0, 0x01, 0xb301);
+ reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
+ }
+
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]);
for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
@@ -2406,17 +2503,17 @@ static void i2c_write(struct gspca_dev *gspca_dev,
}
static void put_tab_to_reg(struct gspca_dev *gspca_dev,
- const __u8 *tab, __u8 tabsize, __u16 addr)
+ const u8 *tab, u8 tabsize, u16 addr)
{
int j;
- __u16 ad = addr;
+ u16 ad = addr;
for (j = 0; j < tabsize; j++)
reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
}
static void usb_exchange(struct gspca_dev *gspca_dev,
- const __u8 data[][4])
+ const u8 data[][4])
{
struct usb_device *dev = gspca_dev->dev;
int i = 0;
@@ -2466,7 +2563,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
};
cam = &gspca_dev->cam;
- sd->bridge = id->driver_info;
+ sd->bridge = id->driver_info >> 8;
+ sd->flags = id->driver_info & 0xff;
sensor = vc032x_probe_sensor(gspca_dev);
switch (sensor) {
case -1:
@@ -2519,8 +2617,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
case SENSOR_MI1320_SOC:
cam->cam_mode = bi_mode;
cam->nmodes = ARRAY_SIZE(bi_mode);
- cam->input_flags = V4L2_IN_ST_VFLIP |
- V4L2_IN_ST_HFLIP;
break;
default:
cam->cam_mode = vc0323_mode;
@@ -2532,14 +2628,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF;
- if (sd->sensor == SENSOR_OV7670) {
- sd->hflip = 1;
- sd->vflip = 1;
- }
+ if (sd->sensor == SENSOR_OV7670)
+ sd->flags |= FL_HFLIP | FL_VFLIP;
sd->lightfreq = FREQ_DEF;
if (sd->sensor != SENSOR_OV7670)
gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
switch (sd->sensor) {
+ case SENSOR_MI1310_SOC:
+ case SENSOR_MI1320_SOC:
case SENSOR_OV7660:
case SENSOR_OV7670:
case SENSOR_PO1200:
@@ -2568,39 +2664,50 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
-/* for OV7660 and OV7670 only */
+/* some sensors only */
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 data;
-
+ u8 data[2], hflip, vflip;
+
+ hflip = sd->hflip;
+ if (sd->flags & FL_HFLIP)
+ hflip = !hflip;
+ vflip = sd->vflip;
+ if (sd->flags & FL_VFLIP)
+ vflip = !vflip;
switch (sd->sensor) {
- case SENSOR_OV7660:
- data = 1;
+ case SENSOR_MI1310_SOC:
+ case SENSOR_MI1320_SOC:
+ data[0] = data[1] = 0; /* select page 0 */
+ i2c_write(gspca_dev, 0xf0, data, 2);
+ data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01;
+ data[1] = 0x02 * hflip
+ | 0x01 * vflip;
+ i2c_write(gspca_dev, 0x20, data, 2);
break;
+ case SENSOR_OV7660:
case SENSOR_OV7670:
- data = 7;
+ data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07;
+ data[0] |= OV7660_MVFP_MIRROR * hflip
+ | OV7660_MVFP_VFLIP * vflip;
+ i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1);
break;
case SENSOR_PO1200:
- data = 0;
- i2c_write(gspca_dev, 0x03, &data, 1);
- data = 0x80 * sd->hflip
- | 0x40 * sd->vflip
+ data[0] = 0;
+ i2c_write(gspca_dev, 0x03, data, 1);
+ data[0] = 0x80 * hflip
+ | 0x40 * vflip
| 0x06;
- i2c_write(gspca_dev, 0x1e, &data, 1);
- return;
- default:
- return;
+ i2c_write(gspca_dev, 0x1e, data, 1);
+ break;
}
- data |= OV7660_MVFP_MIRROR * sd->hflip
- | OV7660_MVFP_VFLIP * sd->vflip;
- i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1);
}
static void setlightfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- static const __u8 (*ov7660_freq_tb[3])[4] =
+ static const u8 (*ov7660_freq_tb[3])[4] =
{ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
if (sd->sensor != SENSOR_OV7660)
@@ -2612,7 +2719,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
static void setsharpness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 data;
+ u8 data;
if (sd->sensor != SENSOR_PO1200)
return;
@@ -2625,9 +2732,9 @@ static void setsharpness(struct gspca_dev *gspca_dev)
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- const __u8 (*init)[4];
- const __u8 *GammaT = NULL;
- const __u8 *MatrixT = NULL;
+ const u8 (*init)[4];
+ const u8 *GammaT = NULL;
+ const u8 *MatrixT = NULL;
int mode;
static const u8 (*mi1320_soc_init[])[4] = {
mi1320_soc_InitSXGA,
@@ -2635,6 +2742,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
mi1320_soc_InitQVGA,
};
+/*fixme: back sensor only*/
+ if (sd->flags & FL_SAMSUNG) {
+ reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
+ reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
+ reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
+ }
+
/* Assume start use the good resolution from gspca_dev->mode */
if (sd->bridge == BRIDGE_VC0321) {
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
@@ -2737,15 +2851,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
/* set the led on 0x0892 0x0896 */
- if (sd->sensor != SENSOR_PO1200) {
- reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ if (sd->sensor == SENSOR_PO1200) {
+ setsharpness(gspca_dev);
+ sethvflip(gspca_dev);
+ reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+ } else if (sd->sensor == SENSOR_MI1310_SOC) {
+ reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
msleep(100);
sethvflip(gspca_dev);
setlightfreq(gspca_dev);
} else {
- setsharpness(gspca_dev);
+ reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ msleep(100);
sethvflip(gspca_dev);
- reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+ setlightfreq(gspca_dev);
}
}
return 0;
@@ -2754,8 +2873,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
+ struct sd *sd = (struct sd *) gspca_dev;
- reg_w(dev, 0x89, 0xffff, 0xffff);
+ if (sd->sensor == SENSOR_MI1310_SOC)
+ reg_w(dev, 0x89, 0x058c, 0x00ff);
+ else
+ reg_w(dev, 0x89, 0xffff, 0xffff);
reg_w(dev, 0xa0, 0x01, 0xb301);
reg_w(dev, 0xa0, 0x09, 0xb003);
}
@@ -2764,15 +2887,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
+ struct sd *sd = (struct sd *) gspca_dev;
if (!gspca_dev->present)
return;
- reg_w(dev, 0x89, 0xffff, 0xffff);
+/*fixme: is this useful?*/
+ if (sd->sensor == SENSOR_MI1310_SOC)
+ reg_w(dev, 0x89, 0x058c, 0x00ff);
+ else
+ reg_w(dev, 0x89, 0xffff, 0xffff);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
- __u8 *data, /* isoc packet */
+ u8 *data, /* isoc packet */
int len) /* iso pkt length */
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2872,21 +3000,12 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
+ static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
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;
- default:
-/* case 2: * V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
+ strcpy((char *) menu->name, freq_nm[menu->index]);
+ return 0;
}
return -EINVAL;
}
@@ -2906,19 +3025,23 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
+#define BF(bridge, flags) \
+ .driver_info = (BRIDGE_ ## bridge << 8) \
+ | (flags)
static const __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x041e, 0x405b), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x15b8, 0x6001), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323},
+ {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
+ {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
+ {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
+ {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)},
+ {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)},
+ {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)},
+ {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)},
+ {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 3d2756f7874a..cdf3357b4c9f 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -7574,7 +7574,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
- .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+ .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
.start = sd_start,
diff --git a/drivers/media/video/hdpvr/hdpvr-control.c b/drivers/media/video/hdpvr/hdpvr-control.c
index 06791749d1a0..5a6b78b8d25d 100644
--- a/drivers/media/video/hdpvr/hdpvr-control.c
+++ b/drivers/media/video/hdpvr/hdpvr-control.c
@@ -178,24 +178,24 @@ error:
int hdpvr_set_options(struct hdpvr_device *dev)
{
- hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
+ hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
- hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
+ hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
dev->options.video_input+1);
- hdpvr_set_audio(dev, dev->options.audio_input+1,
+ hdpvr_set_audio(dev, dev->options.audio_input+1,
dev->options.audio_codec);
- hdpvr_set_bitrate(dev);
- hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+ hdpvr_set_bitrate(dev);
+ hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
dev->options.bitrate_mode);
- hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
+ hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
- hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
- hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast);
- hdpvr_config_call(dev, CTRL_HUE, dev->options.hue);
- hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
- hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness);
+ hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
+ hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast);
+ hdpvr_config_call(dev, CTRL_HUE, dev->options.hue);
+ hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
+ hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness);
- return 0;
+ return 0;
}
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 188bd5aea258..1c9bc94c905c 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -126,7 +126,7 @@ static int device_authorization(struct hdpvr_device *dev)
char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
if (!print_buf) {
v4l2_err(&dev->v4l2_dev, "Out of memory\n");
- goto error;
+ return retval;
}
#endif
@@ -140,7 +140,7 @@ static int device_authorization(struct hdpvr_device *dev)
if (ret != 46) {
v4l2_err(&dev->v4l2_dev,
"unexpected answer of status request, len %d\n", ret);
- goto error;
+ goto unlock;
}
#ifdef HDPVR_DEBUG
else {
@@ -163,7 +163,7 @@ static int device_authorization(struct hdpvr_device *dev)
v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
dev->usbc_buf[1]);
ret = -EINVAL;
- goto error;
+ goto unlock;
}
response = dev->usbc_buf+38;
@@ -188,10 +188,10 @@ static int device_authorization(struct hdpvr_device *dev)
10000);
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"magic request returned %d\n", ret);
- mutex_unlock(&dev->usbc_mutex);
retval = ret != 8;
-error:
+unlock:
+ mutex_unlock(&dev->usbc_mutex);
return retval;
}
@@ -350,6 +350,7 @@ static int hdpvr_probe(struct usb_interface *interface,
mutex_lock(&dev->io_mutex);
if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
+ mutex_unlock(&dev->io_mutex);
v4l2_err(&dev->v4l2_dev,
"allocating transfer buffers failed\n");
goto error;
@@ -381,7 +382,6 @@ static int hdpvr_probe(struct usb_interface *interface,
error:
if (dev) {
- mutex_unlock(&dev->io_mutex);
/* this frees allocated memory */
hdpvr_delete(dev);
}
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
index c4b5d1515c10..296330a0e1e5 100644
--- a/drivers/media/video/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/video/hdpvr/hdpvr-i2c.c
@@ -127,7 +127,6 @@ int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
sizeof(i2c_adap->name));
i2c_adap->algo = &hdpvr_algo;
i2c_adap->class = I2C_CLASS_TV_ANALOG;
- i2c_adap->id = I2C_HW_B_HDPVR;
i2c_adap->owner = THIS_MODULE;
i2c_adap->dev.parent = &dev->udev->dev;
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index d678765cbba2..2eb9dc2ebe59 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -375,6 +375,7 @@ static int hdpvr_open(struct file *file)
* in resumption */
mutex_lock(&dev->io_mutex);
dev->open_count++;
+ mutex_unlock(&dev->io_mutex);
fh->dev = dev;
@@ -383,7 +384,6 @@ static int hdpvr_open(struct file *file)
retval = 0;
err:
- mutex_unlock(&dev->io_mutex);
return retval;
}
@@ -519,8 +519,10 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
mutex_lock(&dev->io_mutex);
- if (video_is_unregistered(dev->video_dev))
+ if (video_is_unregistered(dev->video_dev)) {
+ mutex_unlock(&dev->io_mutex);
return -EIO;
+ }
if (dev->status == STATUS_IDLE) {
if (hdpvr_start_streaming(dev)) {
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 86f2fefe1edf..b92ddcabf0b6 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -122,12 +122,12 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
return 1;
}
-static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
}
-static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
}
@@ -357,9 +357,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x47:
case 0x71:
case 0x2d:
- if (adap->id == I2C_HW_B_CX2388x) {
+ if (adap->id == I2C_HW_B_CX2388x ||
+ adap->id == I2C_HW_B_CX2341X) {
/* Handled by cx88-input */
- name = "CX2388x remote";
+ name = adap->id == I2C_HW_B_CX2341X ? "CX2341x remote"
+ : "CX2388x remote";
ir_type = IR_TYPE_RC5;
ir->get_key = get_key_haup_xvr;
if (hauppauge == 1) {
@@ -392,7 +394,36 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
ir_codes = init_data->ir_codes;
name = init_data->name;
- ir->get_key = init_data->get_key;
+ if (init_data->type)
+ ir_type = init_data->type;
+
+ switch (init_data->internal_get_key_func) {
+ case IR_KBD_GET_KEY_CUSTOM:
+ /* The bridge driver provided us its own function */
+ ir->get_key = init_data->get_key;
+ break;
+ case IR_KBD_GET_KEY_PIXELVIEW:
+ ir->get_key = get_key_pixelview;
+ break;
+ case IR_KBD_GET_KEY_PV951:
+ ir->get_key = get_key_pv951;
+ break;
+ case IR_KBD_GET_KEY_HAUP:
+ ir->get_key = get_key_haup;
+ break;
+ case IR_KBD_GET_KEY_KNC1:
+ ir->get_key = get_key_knc1;
+ break;
+ case IR_KBD_GET_KEY_FUSIONHDTV:
+ ir->get_key = get_key_fusionhdtv;
+ break;
+ case IR_KBD_GET_KEY_HAUP_XVR:
+ ir->get_key = get_key_haup_xvr;
+ break;
+ case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS:
+ ir->get_key = get_key_avermedia_cardbus;
+ break;
+ }
}
/* Make sure we are all setup before going on */
@@ -454,7 +485,8 @@ static int ir_remove(struct i2c_client *client)
static const struct i2c_device_id ir_kbd_id[] = {
/* Generic entry for any IR receiver */
{ "ir_video", 0 },
- /* IR device specific entries could be added here */
+ /* IR device specific entries should be added here */
+ { "ir_rx_z8f0811_haup", 0 },
{ }
};
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 2883c8780760..4873b6ca5801 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -977,26 +977,27 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
/* ------------------------------------------------------------------------- */
-/* AVerMedia PVR-150 Plus (M113) card */
+/* AVerMedia PVR-150 Plus / AVerTV M113 cards with a Daewoo/Partsnic Tuner */
static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
- { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 },
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc034 }, /* NTSC */
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, /* NTSC FM */
{ 0, 0, 0 }
};
static const struct ivtv_card ivtv_card_aver_pvr150 = {
.type = IVTV_CARD_AVER_PVR150PLUS,
- .name = "AVerMedia PVR-150 Plus",
+ .name = "AVerMedia PVR-150 Plus / AVerTV M113 Partsnic (Daewoo) Tuner",
.v4l2_capabilities = IVTV_CAP_ENCODER,
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
.hw_audio_ctrl = IVTV_HW_CX25840,
.hw_muxer = IVTV_HW_GPIO,
- .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+ IVTV_HW_WM8739 | IVTV_HW_GPIO,
.video_inputs = {
{ IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
- { IVTV_CARD_INPUT_SVIDEO1, 1,
- CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 },
{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
},
.audio_inputs = {
@@ -1004,18 +1005,66 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = {
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
- .gpio_init = { .direction = 0x0800, .initial_value = 0 },
- .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
+ /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+ .gpio_init = { .direction = 0xc000, .initial_value = 0 },
+ .gpio_audio_input = { .mask = 0xc000,
+ .tuner = 0x0000,
+ .linein = 0x4000,
+ .radio = 0x8000 },
.tuners = {
- /* This card has a Partsnic PTI-5NF05 tuner */
- { .std = V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
+ /* Subsystem ID's 0xc03[45] have a Partsnic PTI-5NF05 tuner */
+ { .std = V4L2_STD_MN, .tuner = TUNER_PARTSNIC_PTI_5NF05 },
},
.pci_list = ivtv_pci_aver_pvr150,
+ /* Subsystem ID 0xc035 has a TEA5767(?) FM tuner, 0xc034 does not */
.i2c = &ivtv_i2c_radio,
};
/* ------------------------------------------------------------------------- */
+/* AVerMedia UltraTV 1500 MCE (newer non-cx88 version, M113 variant) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_ultra1500mce[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_ultra1500mce = {
+ .type = IVTV_CARD_AVER_ULTRA1500MCE,
+ .name = "AVerMedia UltraTV 1500 MCE / AVerTV M113 Philips Tuner",
+ .v4l2_capabilities = IVTV_CAP_ENCODER,
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_muxer = IVTV_HW_GPIO,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+ IVTV_HW_WM8739 | IVTV_HW_GPIO,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 },
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
+ },
+ .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+ /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+ .gpio_init = { .direction = 0xc000, .initial_value = 0 },
+ .gpio_audio_input = { .mask = 0xc000,
+ .tuner = 0x0000,
+ .linein = 0x4000,
+ .radio = 0x8000 },
+ .tuners = {
+ /* The UltraTV 1500 MCE has a Philips FM1236 MK5 TV/FM tuner */
+ { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ },
+ .pci_list = ivtv_pci_aver_ultra1500mce,
+ .i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
/* AVerMedia EZMaker PCI Deluxe card */
static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
@@ -1180,6 +1229,7 @@ static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_aver_ezmaker,
&ivtv_card_aver_m104,
&ivtv_card_buffalo,
+ &ivtv_card_aver_ultra1500mce,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 0b8fe85fb697..e99a0a255578 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -50,7 +50,8 @@
#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */
#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */
#define IVTV_CARD_BUFFALO_MV5L 25 /* Buffalo PC-MV5L/PCI card */
-#define IVTV_CARD_LAST 25
+#define IVTV_CARD_AVER_ULTRA1500MCE 26 /* AVerMedia UltraTV 1500 MCE */
+#define IVTV_CARD_LAST 26
/* Variants of existing cards but with the same PCI IDs. The driver
detects these based on other device information.
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 558f8a837ff4..63ea0fb66063 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -186,6 +186,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
"\t\t\t25 = AverMedia M104 (not yet working)\n"
"\t\t\t26 = Buffalo PC-MV5L/PCI\n"
+ "\t\t\t27 = AVerMedia UltraTV 1500 MCE\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
@@ -218,7 +219,7 @@ MODULE_PARM_DESC(ivtv_yuv_mode,
"\t\t\tDefault: 0 (interlaced)");
MODULE_PARM_DESC(ivtv_yuv_threshold,
"If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n"
- "\t\t\tDefault: 480");;
+ "\t\t\tDefault: 480");
MODULE_PARM_DESC(enc_mpg_buffers,
"Encoder MPG Buffers (in MB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS));
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 85ac707228e7..aede061cae5d 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -236,18 +236,6 @@ static int subdev_s_radio(struct v4l2_subdev *sd)
return 0;
}
-static int subdev_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
-{
- struct ivtv *itv = sd_to_ivtv(sd);
- u16 mask, data;
-
- mask = itv->card->gpio_audio_input.mask;
- data = itv->card->gpio_audio_input.tuner;
- if (mask)
- write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
- return 0;
-}
-
static int subdev_s_audio_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
@@ -344,7 +332,6 @@ static const struct v4l2_subdev_core_ops subdev_core_ops = {
.g_ctrl = subdev_g_ctrl,
.s_ctrl = subdev_s_ctrl,
.queryctrl = subdev_queryctrl,
- .s_std = subdev_s_std,
};
static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index e52aa322b134..8f15a31d3f66 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -509,7 +509,6 @@ static struct i2c_algorithm ivtv_algo = {
/* template for our-bit banger */
static struct i2c_adapter ivtv_i2c_adap_hw_template = {
.name = "ivtv i2c driver",
- .id = I2C_HW_B_CX2341X,
.algo = &ivtv_algo,
.algo_data = NULL, /* filled from template */
.owner = THIS_MODULE,
@@ -560,7 +559,6 @@ static int ivtv_getsda_old(void *data)
/* template for i2c-bit-algo */
static struct i2c_adapter ivtv_i2c_adap_template = {
.name = "ivtv i2c driver",
- .id = I2C_HW_B_CX2341X,
.algo = NULL, /* set by i2c-algo-bit */
.algo_data = NULL, /* filled from template */
.owner = THIS_MODULE,
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 1d66855a379a..d0765bed79c9 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1915,8 +1915,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
}
static struct pci_device_id meye_pci_tbl[] = {
- { PCI_VENDOR_ID_KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 },
{ }
};
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 4d794b42d6cd..45388d2ce2fd 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -13,13 +13,13 @@
#include <linux/i2c.h>
#include <linux/log2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
/* mt9m001 i2c address 0x5d
- * The platform has to define i2c_board_info
- * and call i2c_register_board_info() */
+ * The platform has to define ctruct i2c_board_info objects and link to them
+ * from struct soc_camera_link */
/* mt9m001 selected register addresses */
#define MT9M001_CHIP_VERSION 0x00
@@ -39,6 +39,13 @@
#define MT9M001_GLOBAL_GAIN 0x35
#define MT9M001_CHIP_ENABLE 0xF1
+#define MT9M001_MAX_WIDTH 1280
+#define MT9M001_MAX_HEIGHT 1024
+#define MT9M001_MIN_WIDTH 48
+#define MT9M001_MIN_HEIGHT 32
+#define MT9M001_COLUMN_SKIP 20
+#define MT9M001_ROW_SKIP 12
+
static const struct soc_camera_data_format mt9m001_colour_formats[] = {
/* Order important: first natively supported,
* second supported with a GPIO extender */
@@ -69,12 +76,20 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = {
};
struct mt9m001 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
+ struct v4l2_rect rect; /* Sensor window */
+ __u32 fourcc;
int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+ unsigned int gain;
+ unsigned int exposure;
unsigned char autoexposure;
};
+static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9m001, subdev);
+}
+
static int reg_read(struct i2c_client *client, const u8 reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
@@ -109,35 +124,20 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
return reg_write(client, reg, ret & ~data);
}
-static int mt9m001_init(struct soc_camera_device *icd)
+static int mt9m001_init(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
int ret;
- dev_dbg(icd->vdev->parent, "%s\n", __func__);
+ dev_dbg(&client->dev, "%s\n", __func__);
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
- /* The camera could have been already on, we reset it additionally */
- if (icl->reset)
- ret = icl->reset(&client->dev);
- else
- ret = -ENODEV;
+ /*
+ * We don't know, whether platform provides reset, issue a soft reset
+ * too. This returns all registers to their default values.
+ */
+ ret = reg_write(client, MT9M001_RESET, 1);
+ if (!ret)
+ ret = reg_write(client, MT9M001_RESET, 0);
- if (ret < 0) {
- /* Either no platform reset, or platform reset failed */
- ret = reg_write(client, MT9M001_RESET, 1);
- if (!ret)
- ret = reg_write(client, MT9M001_RESET, 0);
- }
/* Disable chip, synchronous option update */
if (!ret)
ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
@@ -145,36 +145,12 @@ static int mt9m001_init(struct soc_camera_device *icd)
return ret;
}
-static int mt9m001_release(struct soc_camera_device *icd)
+static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
-
- /* Disable the chip */
- reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
-
- if (icl->power)
- icl->power(&client->dev, 0);
-
- return 0;
-}
+ struct i2c_client *client = sd->priv;
-static int mt9m001_start_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* Switch to master "normal" mode */
- if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0)
- return -EIO;
- return 0;
-}
-
-static int mt9m001_stop_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* Stop sensor readout */
- if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0)
+ /* Switch to master "normal" mode or stop sensor readout */
+ if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
return -EIO;
return 0;
}
@@ -182,8 +158,7 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd)
static int mt9m001_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
/* Only one width bit may be set */
@@ -205,8 +180,7 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
/* MT9M001 has all capture_format parameters fixed */
unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
@@ -220,13 +194,35 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
return soc_camera_apply_sensor_flags(icl, flags);
}
-static int mt9m001_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_rect rect = a->c;
+ struct soc_camera_device *icd = client->dev.platform_data;
int ret;
const u16 hblank = 9, vblank = 25;
+ unsigned int total_h;
+
+ if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 ||
+ mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16)
+ /*
+ * Bayer format - even number of rows for simplicity,
+ * but let the user play with the top row.
+ */
+ rect.height = ALIGN(rect.height, 2);
+
+ /* Datasheet requirement: see register description */
+ rect.width = ALIGN(rect.width, 2);
+ rect.left = ALIGN(rect.left, 2);
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
+
+ total_h = rect.height + icd->y_skip_top + vblank;
/* Blanking and start values - default... */
ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
@@ -236,66 +232,126 @@ static int mt9m001_set_crop(struct soc_camera_device *icd,
/* The caller provides a supported format, as verified per
* call to icd->try_fmt() */
if (!ret)
- ret = reg_write(client, MT9M001_COLUMN_START, rect->left);
+ ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
if (!ret)
- ret = reg_write(client, MT9M001_ROW_START, rect->top);
+ ret = reg_write(client, MT9M001_ROW_START, rect.top);
if (!ret)
- ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1);
+ ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
if (!ret)
ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
- rect->height + icd->y_skip_top - 1);
+ rect.height + icd->y_skip_top - 1);
if (!ret && mt9m001->autoexposure) {
- ret = reg_write(client, MT9M001_SHUTTER_WIDTH,
- rect->height + icd->y_skip_top + vblank);
+ ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h);
if (!ret) {
const struct v4l2_queryctrl *qctrl =
soc_camera_find_qctrl(icd->ops,
V4L2_CID_EXPOSURE);
- icd->exposure = (524 + (rect->height + icd->y_skip_top +
- vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9m001->exposure = (524 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
1048 + qctrl->minimum;
}
}
+ if (!ret)
+ mt9m001->rect = rect;
+
return ret;
}
-static int mt9m001_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+ a->c = mt9m001->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9M001_COLUMN_SKIP;
+ a->bounds.top = MT9M001_ROW_SKIP;
+ a->bounds.width = MT9M001_MAX_WIDTH;
+ a->bounds.height = MT9M001_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9m001_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = f->fmt.pix.width,
- .height = f->fmt.pix.height,
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = mt9m001->rect.width;
+ pix->height = mt9m001->rect.height;
+ pix->pixelformat = mt9m001->fourcc;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_crop a = {
+ .c = {
+ .left = mt9m001->rect.left,
+ .top = mt9m001->rect.top,
+ .width = pix->width,
+ .height = pix->height,
+ },
};
+ int ret;
/* No support for scaling so far, just crop. TODO: use skipping */
- return mt9m001_set_crop(icd, &rect);
+ ret = mt9m001_s_crop(sd, &a);
+ if (!ret) {
+ pix->width = mt9m001->rect.width;
+ pix->height = mt9m001->rect.height;
+ mt9m001->fourcc = pix->pixelformat;
+ }
+
+ return ret;
}
-static int mt9m001_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
+ struct i2c_client *client = sd->priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
- v4l_bound_align_image(&pix->width, 48, 1280, 1,
- &pix->height, 32 + icd->y_skip_top,
- 1024 + icd->y_skip_top, 0, 0);
+ v4l_bound_align_image(&pix->width, MT9M001_MIN_WIDTH,
+ MT9M001_MAX_WIDTH, 1,
+ &pix->height, MT9M001_MIN_HEIGHT + icd->y_skip_top,
+ MT9M001_MAX_HEIGHT + icd->y_skip_top, 0, 0);
+
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
+ pix->pixelformat == V4L2_PIX_FMT_SBGGR16)
+ pix->height = ALIGN(pix->height - 1, 2);
return 0;
}
-static int mt9m001_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9m001->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9m001->model;
@@ -305,10 +361,10 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m001_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m001_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -325,10 +381,10 @@ static int mt9m001_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9m001_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m001_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -381,39 +437,17 @@ static const struct v4l2_queryctrl mt9m001_controls[] = {
}
};
-static int mt9m001_video_probe(struct soc_camera_device *);
-static void mt9m001_video_remove(struct soc_camera_device *);
-static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *);
-static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *);
-
static struct soc_camera_ops mt9m001_ops = {
- .owner = THIS_MODULE,
- .probe = mt9m001_video_probe,
- .remove = mt9m001_video_remove,
- .init = mt9m001_init,
- .release = mt9m001_release,
- .start_capture = mt9m001_start_capture,
- .stop_capture = mt9m001_stop_capture,
- .set_crop = mt9m001_set_crop,
- .set_fmt = mt9m001_set_fmt,
- .try_fmt = mt9m001_try_fmt,
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.controls = mt9m001_controls,
.num_controls = ARRAY_SIZE(mt9m001_controls),
- .get_control = mt9m001_get_control,
- .set_control = mt9m001_set_control,
- .get_chip_id = mt9m001_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9m001_get_register,
- .set_register = mt9m001_set_register,
-#endif
};
-static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
int data;
switch (ctrl->id) {
@@ -426,14 +460,21 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9m001->autoexposure;
break;
+ case V4L2_CID_GAIN:
+ ctrl->value = mt9m001->gain;
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = mt9m001->exposure;
+ break;
}
return 0;
}
-static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
const struct v4l2_queryctrl *qctrl;
int data;
@@ -460,7 +501,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long range = qctrl->default_value - qctrl->minimum;
data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
- dev_dbg(&icd->dev, "Setting gain %d\n", data);
+ dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
if (data < 0)
return -EIO;
@@ -478,7 +519,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
else
data = ((gain - 64) * 7 + 28) / 56 + 96;
- dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
+ dev_dbg(&client->dev, "Setting gain from %d to %d\n",
reg_read(client, MT9M001_GLOBAL_GAIN), data);
data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
if (data < 0)
@@ -486,7 +527,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
}
/* Success */
- icd->gain = ctrl->value;
+ mt9m001->gain = ctrl->value;
break;
case V4L2_CID_EXPOSURE:
/* mt9m001 has maximum == default */
@@ -497,23 +538,27 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 +
range / 2) / range + 1;
- dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n",
- reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
+ dev_dbg(&client->dev,
+ "Setting shutter width from %d to %lu\n",
+ reg_read(client, MT9M001_SHUTTER_WIDTH),
+ shutter);
if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
return -EIO;
- icd->exposure = ctrl->value;
+ mt9m001->exposure = ctrl->value;
mt9m001->autoexposure = 0;
}
break;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->value) {
const u16 vblank = 25;
- if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height +
- icd->y_skip_top + vblank) < 0)
+ unsigned int total_h = mt9m001->rect.height +
+ icd->y_skip_top + vblank;
+ if (reg_write(client, MT9M001_SHUTTER_WIDTH,
+ total_h) < 0)
return -EIO;
qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
- icd->exposure = (524 + (icd->height + icd->y_skip_top + vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9m001->exposure = (524 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
1048 + qctrl->minimum;
mt9m001->autoexposure = 1;
} else
@@ -525,14 +570,14 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
/* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one */
-static int mt9m001_video_probe(struct soc_camera_device *icd)
+static int mt9m001_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
s32 data;
- int ret;
unsigned long flags;
+ int ret;
/* We must have a parent by now. And it cannot be a wrong one.
* So this entire test is completely redundant. */
@@ -542,7 +587,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
/* Enable the chip */
data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
- dev_dbg(&icd->dev, "write: %d\n", data);
+ dev_dbg(&client->dev, "write: %d\n", data);
/* Read out the chip version register */
data = reg_read(client, MT9M001_CHIP_VERSION);
@@ -559,10 +604,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
icd->formats = mt9m001_monochrome_formats;
break;
default:
- ret = -ENODEV;
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"No MT9M001 chip detected, register read %x\n", data);
- goto ei2c;
+ return -ENODEV;
}
icd->num_formats = 0;
@@ -585,42 +629,72 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
if (flags & SOCAM_DATAWIDTH_8)
icd->num_formats++;
- dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+ mt9m001->fourcc = icd->formats->fourcc;
+
+ dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
data == 0x8431 ? "C12STM" : "C12ST");
- /* Now that we know the model, we can start video */
- ret = soc_camera_video_start(icd);
- if (ret)
- goto eisis;
+ ret = mt9m001_init(client);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to initialise the camera\n");
- return 0;
+ /* mt9m001_init() has reset the chip, returning registers to defaults */
+ mt9m001->gain = 64;
+ mt9m001->exposure = 255;
-eisis:
-ei2c:
return ret;
}
static void mt9m001_video_remove(struct soc_camera_device *icd)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
+ dev_dbg(&icd->dev, "Video removed: %p, %p\n",
icd->dev.parent, icd->vdev);
- soc_camera_video_stop(icd);
if (icl->free_bus)
icl->free_bus(icl);
}
+static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
+ .g_ctrl = mt9m001_g_ctrl,
+ .s_ctrl = mt9m001_s_ctrl,
+ .g_chip_ident = mt9m001_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9m001_g_register,
+ .s_register = mt9m001_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
+ .s_stream = mt9m001_s_stream,
+ .s_fmt = mt9m001_s_fmt,
+ .g_fmt = mt9m001_g_fmt,
+ .try_fmt = mt9m001_try_fmt,
+ .s_crop = mt9m001_s_crop,
+ .g_crop = mt9m001_g_crop,
+ .cropcap = mt9m001_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9m001_subdev_ops = {
+ .core = &mt9m001_subdev_core_ops,
+ .video = &mt9m001_subdev_video_ops,
+};
+
static int mt9m001_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9m001 *mt9m001;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9M001 driver needs platform data\n");
return -EINVAL;
@@ -636,43 +710,40 @@ static int mt9m001_probe(struct i2c_client *client,
if (!mt9m001)
return -ENOMEM;
- mt9m001->client = client;
- i2c_set_clientdata(client, mt9m001);
+ v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
/* Second stage probe - when a capture adapter is there */
- icd = &mt9m001->icd;
- icd->ops = &mt9m001_ops;
- icd->control = &client->dev;
- icd->x_min = 20;
- icd->y_min = 12;
- icd->x_current = 20;
- icd->y_current = 12;
- icd->width_min = 48;
- icd->width_max = 1280;
- icd->height_min = 32;
- icd->height_max = 1024;
- icd->y_skip_top = 1;
- icd->iface = icl->bus_id;
+ icd->ops = &mt9m001_ops;
+ icd->y_skip_top = 0;
+
+ mt9m001->rect.left = MT9M001_COLUMN_SKIP;
+ mt9m001->rect.top = MT9M001_ROW_SKIP;
+ mt9m001->rect.width = MT9M001_MAX_WIDTH;
+ mt9m001->rect.height = MT9M001_MAX_HEIGHT;
+
/* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width */
mt9m001->autoexposure = 1;
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
-
- return 0;
+ ret = mt9m001_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9m001);
+ }
-eisdr:
- kfree(mt9m001);
return ret;
}
static int mt9m001_remove(struct i2c_client *client)
{
- struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&mt9m001->icd);
+ icd->ops = NULL;
+ mt9m001_video_remove(icd);
+ i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9m001);
return 0;
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index fc5e2de03766..90da699601ea 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -148,12 +148,12 @@ enum mt9m111_context {
};
struct mt9m111 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
enum mt9m111_context context;
struct v4l2_rect rect;
u32 pixfmt;
+ unsigned int gain;
unsigned char autoexposure;
unsigned char datawidth;
unsigned int powered:1;
@@ -166,6 +166,11 @@ struct mt9m111 {
unsigned int autowhitebalance:1;
};
+static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
+}
+
static int reg_page_map_set(struct i2c_client *client, const u16 reg)
{
int ret;
@@ -190,7 +195,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
ret = reg_page_map_set(client, reg);
if (!ret)
- ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff)));
+ ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff));
dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret);
return ret;
@@ -203,7 +208,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
ret = reg_page_map_set(client, reg);
if (!ret)
- ret = i2c_smbus_write_word_data(client, (reg & 0xff),
+ ret = i2c_smbus_write_word_data(client, reg & 0xff,
swab16(data));
dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
return ret;
@@ -229,10 +234,9 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
return mt9m111_reg_write(client, reg, ret & ~data);
}
-static int mt9m111_set_context(struct soc_camera_device *icd,
+static int mt9m111_set_context(struct i2c_client *client,
enum mt9m111_context ctxt)
{
- struct i2c_client *client = to_i2c_client(icd->control);
int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
| MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
| MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
@@ -246,17 +250,16 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
return reg_write(CONTEXT_CONTROL, valA);
}
-static int mt9m111_setup_rect(struct soc_camera_device *icd,
+static int mt9m111_setup_rect(struct i2c_client *client,
struct v4l2_rect *rect)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret, is_raw_format;
int width = rect->width;
int height = rect->height;
- if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
- || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
+ if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
+ mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)
is_raw_format = 1;
else
is_raw_format = 0;
@@ -292,9 +295,8 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd,
return ret;
}
-static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
+static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
{
- struct i2c_client *client = to_i2c_client(icd->control);
int ret;
ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
@@ -303,19 +305,19 @@ static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
return ret;
}
-static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd)
+static int mt9m111_setfmt_bayer8(struct i2c_client *client)
{
- return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER);
+ return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER);
}
-static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd)
+static int mt9m111_setfmt_bayer10(struct i2c_client *client)
{
- return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP);
+ return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP);
}
-static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
+static int mt9m111_setfmt_rgb565(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int val = 0;
if (mt9m111->swap_rgb_red_blue)
@@ -324,12 +326,12 @@ static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
- return mt9m111_setup_pixfmt(icd, val);
+ return mt9m111_setup_pixfmt(client, val);
}
-static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
+static int mt9m111_setfmt_rgb555(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int val = 0;
if (mt9m111->swap_rgb_red_blue)
@@ -338,12 +340,12 @@ static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
- return mt9m111_setup_pixfmt(icd, val);
+ return mt9m111_setup_pixfmt(client, val);
}
-static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
+static int mt9m111_setfmt_yuv(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int val = 0;
if (mt9m111->swap_yuv_cb_cr)
@@ -351,52 +353,22 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
if (mt9m111->swap_yuv_y_chromas)
val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
- return mt9m111_setup_pixfmt(icd, val);
+ return mt9m111_setup_pixfmt(client, val);
}
-static int mt9m111_enable(struct soc_camera_device *icd)
+static int mt9m111_enable(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
if (!ret)
mt9m111->powered = 1;
return ret;
}
-static int mt9m111_disable(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
- int ret;
-
- ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
- if (!ret)
- mt9m111->powered = 0;
-
- if (icl->power)
- icl->power(&client->dev, 0);
-
- return ret;
-}
-
-static int mt9m111_reset(struct soc_camera_device *icd)
+static int mt9m111_reset(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
int ret;
ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -406,26 +378,12 @@ static int mt9m111_reset(struct soc_camera_device *icd)
ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
| MT9M111_RESET_RESET_SOC);
- if (icl->reset)
- icl->reset(&client->dev);
-
return ret;
}
-static int mt9m111_start_capture(struct soc_camera_device *icd)
-{
- return 0;
-}
-
-static int mt9m111_stop_capture(struct soc_camera_device *icd)
-{
- return 0;
-}
-
static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
@@ -438,62 +396,126 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
return 0;
}
-static int mt9m111_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9m111_make_rect(struct i2c_client *client,
+ struct v4l2_rect *rect)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
+ mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) {
+ /* Bayer format - even size lengths */
+ rect->width = ALIGN(rect->width, 2);
+ rect->height = ALIGN(rect->height, 2);
+ /* Let the user play with the starting pixel */
+ }
+
+ /* FIXME: the datasheet doesn't specify minimum sizes */
+ soc_camera_limit_side(&rect->left, &rect->width,
+ MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect->top, &rect->height,
+ MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
+
+ return mt9m111_setup_rect(client, rect);
+}
+
+static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct v4l2_rect rect = a->c;
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
- dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
- __func__, rect->left, rect->top, rect->width,
- rect->height);
+ dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
+ __func__, rect.left, rect.top, rect.width, rect.height);
- ret = mt9m111_setup_rect(icd, rect);
+ ret = mt9m111_make_rect(client, &rect);
if (!ret)
- mt9m111->rect = *rect;
+ mt9m111->rect = rect;
return ret;
}
-static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
+static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ a->c = mt9m111->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9M111_MIN_DARK_COLS;
+ a->bounds.top = MT9M111_MIN_DARK_ROWS;
+ a->bounds.width = MT9M111_MAX_WIDTH;
+ a->bounds.height = MT9M111_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = mt9m111->rect.width;
+ pix->height = mt9m111->rect.height;
+ pix->pixelformat = mt9m111->pixfmt;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt)
+{
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
switch (pixfmt) {
case V4L2_PIX_FMT_SBGGR8:
- ret = mt9m111_setfmt_bayer8(icd);
+ ret = mt9m111_setfmt_bayer8(client);
break;
case V4L2_PIX_FMT_SBGGR16:
- ret = mt9m111_setfmt_bayer10(icd);
+ ret = mt9m111_setfmt_bayer10(client);
break;
case V4L2_PIX_FMT_RGB555:
- ret = mt9m111_setfmt_rgb555(icd);
+ ret = mt9m111_setfmt_rgb555(client);
break;
case V4L2_PIX_FMT_RGB565:
- ret = mt9m111_setfmt_rgb565(icd);
+ ret = mt9m111_setfmt_rgb565(client);
break;
case V4L2_PIX_FMT_UYVY:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 0;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
case V4L2_PIX_FMT_VYUY:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 1;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
case V4L2_PIX_FMT_YUYV:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 0;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
case V4L2_PIX_FMT_YVYU:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 1;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
default:
- dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt);
+ dev_err(&client->dev, "Pixel format not handled : %x\n",
+ pixfmt);
ret = -EINVAL;
}
@@ -503,10 +525,10 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
return ret;
}
-static int mt9m111_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_rect rect = {
.left = mt9m111->rect.left,
@@ -516,40 +538,56 @@ static int mt9m111_set_fmt(struct soc_camera_device *icd,
};
int ret;
- dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
- __func__, pix->pixelformat, rect.left, rect.top, rect.width,
- rect.height);
+ dev_dbg(&client->dev,
+ "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
+ pix->pixelformat, rect.left, rect.top, rect.width, rect.height);
- ret = mt9m111_setup_rect(icd, &rect);
+ ret = mt9m111_make_rect(client, &rect);
if (!ret)
- ret = mt9m111_set_pixfmt(icd, pix->pixelformat);
+ ret = mt9m111_set_pixfmt(client, pix->pixelformat);
if (!ret)
mt9m111->rect = rect;
return ret;
}
-static int mt9m111_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
+ bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
+ pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
+
+ /*
+ * With Bayer format enforce even side lengths, but let the user play
+ * with the starting pixel
+ */
if (pix->height > MT9M111_MAX_HEIGHT)
pix->height = MT9M111_MAX_HEIGHT;
+ else if (pix->height < 2)
+ pix->height = 2;
+ else if (bayer)
+ pix->height = ALIGN(pix->height, 2);
+
if (pix->width > MT9M111_MAX_WIDTH)
pix->width = MT9M111_MAX_WIDTH;
+ else if (pix->width < 2)
+ pix->width = 2;
+ else if (bayer)
+ pix->width = ALIGN(pix->width, 2);
return 0;
}
-static int mt9m111_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9m111->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9m111->model;
@@ -559,11 +597,11 @@ static int mt9m111_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m111_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m111_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
+ struct i2c_client *client = sd->priv;
int val;
- struct i2c_client *client = to_i2c_client(icd->control);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
@@ -580,10 +618,10 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9m111_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m111_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
@@ -635,45 +673,21 @@ static const struct v4l2_queryctrl mt9m111_controls[] = {
}
};
-static int mt9m111_video_probe(struct soc_camera_device *);
-static void mt9m111_video_remove(struct soc_camera_device *);
-static int mt9m111_get_control(struct soc_camera_device *,
- struct v4l2_control *);
-static int mt9m111_set_control(struct soc_camera_device *,
- struct v4l2_control *);
static int mt9m111_resume(struct soc_camera_device *icd);
-static int mt9m111_init(struct soc_camera_device *icd);
-static int mt9m111_release(struct soc_camera_device *icd);
+static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state);
static struct soc_camera_ops mt9m111_ops = {
- .owner = THIS_MODULE,
- .probe = mt9m111_video_probe,
- .remove = mt9m111_video_remove,
- .init = mt9m111_init,
+ .suspend = mt9m111_suspend,
.resume = mt9m111_resume,
- .release = mt9m111_release,
- .start_capture = mt9m111_start_capture,
- .stop_capture = mt9m111_stop_capture,
- .set_crop = mt9m111_set_crop,
- .set_fmt = mt9m111_set_fmt,
- .try_fmt = mt9m111_try_fmt,
.query_bus_param = mt9m111_query_bus_param,
.set_bus_param = mt9m111_set_bus_param,
.controls = mt9m111_controls,
.num_controls = ARRAY_SIZE(mt9m111_controls),
- .get_control = mt9m111_get_control,
- .set_control = mt9m111_set_control,
- .get_chip_id = mt9m111_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9m111_get_register,
- .set_register = mt9m111_set_register,
-#endif
};
-static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
+static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
if (mt9m111->context == HIGHPOWER) {
@@ -691,9 +705,8 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
return ret;
}
-static int mt9m111_get_global_gain(struct soc_camera_device *icd)
+static int mt9m111_get_global_gain(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
int data;
data = reg_read(GLOBAL_GAIN);
@@ -703,15 +716,15 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd)
return data;
}
-static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
+static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
u16 val;
if (gain > 63 * 2 * 2)
return -EINVAL;
- icd->gain = gain;
+ mt9m111->gain = gain;
if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
val = (1 << 10) | (1 << 9) | (gain / 4);
else if ((gain >= 64) && (gain < 64 * 2))
@@ -722,10 +735,9 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
return reg_write(GLOBAL_GAIN, val);
}
-static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
+static int mt9m111_set_autoexposure(struct i2c_client *client, int on)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
if (on)
@@ -739,10 +751,9 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
return ret;
}
-static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
+static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
if (on)
@@ -756,11 +767,10 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
return ret;
}
-static int mt9m111_get_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int data;
switch (ctrl->id) {
@@ -785,7 +795,7 @@ static int mt9m111_get_control(struct soc_camera_device *icd,
ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
break;
case V4L2_CID_GAIN:
- data = mt9m111_get_global_gain(icd);
+ data = mt9m111_get_global_gain(client);
if (data < 0)
return data;
ctrl->value = data;
@@ -800,37 +810,36 @@ static int mt9m111_get_control(struct soc_camera_device *icd,
return 0;
}
-static int mt9m111_set_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
const struct v4l2_queryctrl *qctrl;
int ret;
qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
-
if (!qctrl)
return -EINVAL;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
mt9m111->vflip = ctrl->value;
- ret = mt9m111_set_flip(icd, ctrl->value,
+ ret = mt9m111_set_flip(client, ctrl->value,
MT9M111_RMB_MIRROR_ROWS);
break;
case V4L2_CID_HFLIP:
mt9m111->hflip = ctrl->value;
- ret = mt9m111_set_flip(icd, ctrl->value,
+ ret = mt9m111_set_flip(client, ctrl->value,
MT9M111_RMB_MIRROR_COLS);
break;
case V4L2_CID_GAIN:
- ret = mt9m111_set_global_gain(icd, ctrl->value);
+ ret = mt9m111_set_global_gain(client, ctrl->value);
break;
case V4L2_CID_EXPOSURE_AUTO:
- ret = mt9m111_set_autoexposure(icd, ctrl->value);
+ ret = mt9m111_set_autoexposure(client, ctrl->value);
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = mt9m111_set_autowhitebalance(icd, ctrl->value);
+ ret = mt9m111_set_autowhitebalance(client, ctrl->value);
break;
default:
ret = -EINVAL;
@@ -839,62 +848,62 @@ static int mt9m111_set_control(struct soc_camera_device *icd,
return ret;
}
-static int mt9m111_restore_state(struct soc_camera_device *icd)
+static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-
- mt9m111_set_context(icd, mt9m111->context);
- mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
- mt9m111_setup_rect(icd, &mt9m111->rect);
- mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
- mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
- mt9m111_set_global_gain(icd, icd->gain);
- mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
- mt9m111_set_autowhitebalance(icd, mt9m111->autowhitebalance);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ mt9m111->gain = mt9m111_get_global_gain(client);
+
+ return 0;
+}
+
+static int mt9m111_restore_state(struct i2c_client *client)
+{
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ mt9m111_set_context(client, mt9m111->context);
+ mt9m111_set_pixfmt(client, mt9m111->pixfmt);
+ mt9m111_setup_rect(client, &mt9m111->rect);
+ mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+ mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+ mt9m111_set_global_gain(client, mt9m111->gain);
+ mt9m111_set_autoexposure(client, mt9m111->autoexposure);
+ mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance);
return 0;
}
static int mt9m111_resume(struct soc_camera_device *icd)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret = 0;
if (mt9m111->powered) {
- ret = mt9m111_enable(icd);
+ ret = mt9m111_enable(client);
if (!ret)
- ret = mt9m111_reset(icd);
+ ret = mt9m111_reset(client);
if (!ret)
- ret = mt9m111_restore_state(icd);
+ ret = mt9m111_restore_state(client);
}
return ret;
}
-static int mt9m111_init(struct soc_camera_device *icd)
+static int mt9m111_init(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
mt9m111->context = HIGHPOWER;
- ret = mt9m111_enable(icd);
+ ret = mt9m111_enable(client);
if (!ret)
- ret = mt9m111_reset(icd);
+ ret = mt9m111_reset(client);
if (!ret)
- ret = mt9m111_set_context(icd, mt9m111->context);
+ ret = mt9m111_set_context(client, mt9m111->context);
if (!ret)
- ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+ ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure);
if (ret)
- dev_err(&icd->dev, "mt9m11x init failed: %d\n", ret);
- return ret;
-}
-
-static int mt9m111_release(struct soc_camera_device *icd)
-{
- int ret;
-
- ret = mt9m111_disable(icd);
- if (ret < 0)
- dev_err(&icd->dev, "mt9m11x release failed: %d\n", ret);
-
+ dev_err(&client->dev, "mt9m11x init failed: %d\n", ret);
return ret;
}
@@ -902,10 +911,10 @@ static int mt9m111_release(struct soc_camera_device *icd)
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
*/
-static int mt9m111_video_probe(struct soc_camera_device *icd)
+static int mt9m111_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
s32 data;
int ret;
@@ -917,10 +926,13 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
return -ENODEV;
- ret = mt9m111_enable(icd);
- if (ret)
- goto ei2c;
- ret = mt9m111_reset(icd);
+ mt9m111->autoexposure = 1;
+ mt9m111->autowhitebalance = 1;
+
+ mt9m111->swap_rgb_even_odd = 1;
+ mt9m111->swap_rgb_red_blue = 1;
+
+ ret = mt9m111_init(client);
if (ret)
goto ei2c;
@@ -935,7 +947,7 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
break;
default:
ret = -ENODEV;
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"No MT9M11x chip detected, register read %x\n", data);
goto ei2c;
}
@@ -943,42 +955,51 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
icd->formats = mt9m111_colour_formats;
icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
- dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data);
+ dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data);
- ret = soc_camera_video_start(icd);
- if (ret)
- goto eisis;
-
- mt9m111->autoexposure = 1;
- mt9m111->autowhitebalance = 1;
-
- mt9m111->swap_rgb_even_odd = 1;
- mt9m111->swap_rgb_red_blue = 1;
-
- return 0;
-eisis:
ei2c:
return ret;
}
-static void mt9m111_video_remove(struct soc_camera_device *icd)
-{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
+ .g_ctrl = mt9m111_g_ctrl,
+ .s_ctrl = mt9m111_s_ctrl,
+ .g_chip_ident = mt9m111_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9m111_g_register,
+ .s_register = mt9m111_s_register,
+#endif
+};
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr,
- mt9m111->icd.dev.parent, mt9m111->icd.vdev);
- soc_camera_video_stop(&mt9m111->icd);
-}
+static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
+ .s_fmt = mt9m111_s_fmt,
+ .g_fmt = mt9m111_g_fmt,
+ .try_fmt = mt9m111_try_fmt,
+ .s_crop = mt9m111_s_crop,
+ .g_crop = mt9m111_g_crop,
+ .cropcap = mt9m111_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9m111_subdev_ops = {
+ .core = &mt9m111_subdev_core_ops,
+ .video = &mt9m111_subdev_video_ops,
+};
static int mt9m111_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9m111 *mt9m111;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9M11x: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9M11x driver needs platform data\n");
return -EINVAL;
@@ -994,38 +1015,35 @@ static int mt9m111_probe(struct i2c_client *client,
if (!mt9m111)
return -ENOMEM;
- mt9m111->client = client;
- i2c_set_clientdata(client, mt9m111);
+ v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
/* Second stage probe - when a capture adapter is there */
- icd = &mt9m111->icd;
- icd->ops = &mt9m111_ops;
- icd->control = &client->dev;
- icd->x_min = MT9M111_MIN_DARK_COLS;
- icd->y_min = MT9M111_MIN_DARK_ROWS;
- icd->x_current = icd->x_min;
- icd->y_current = icd->y_min;
- icd->width_min = MT9M111_MIN_DARK_ROWS;
- icd->width_max = MT9M111_MAX_WIDTH;
- icd->height_min = MT9M111_MIN_DARK_COLS;
- icd->height_max = MT9M111_MAX_HEIGHT;
- icd->y_skip_top = 0;
- icd->iface = icl->bus_id;
-
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
- return 0;
+ icd->ops = &mt9m111_ops;
+ icd->y_skip_top = 0;
+
+ mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
+ mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
+ mt9m111->rect.width = MT9M111_MAX_WIDTH;
+ mt9m111->rect.height = MT9M111_MAX_HEIGHT;
+
+ ret = mt9m111_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9m111);
+ }
-eisdr:
- kfree(mt9m111);
return ret;
}
static int mt9m111_remove(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
- soc_camera_device_unregister(&mt9m111->icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9m111);
return 0;
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index 4207fb342670..6966f644977e 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -13,13 +13,13 @@
#include <linux/i2c.h>
#include <linux/log2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
/* mt9t031 i2c address 0x5d
- * The platform has to define i2c_board_info
- * and call i2c_register_board_info() */
+ * The platform has to define i2c_board_info and link to it from
+ * struct soc_camera_link */
/* mt9t031 selected register addresses */
#define MT9T031_CHIP_VERSION 0x00
@@ -47,7 +47,7 @@
#define MT9T031_MAX_HEIGHT 1536
#define MT9T031_MAX_WIDTH 2048
#define MT9T031_MIN_HEIGHT 2
-#define MT9T031_MIN_WIDTH 2
+#define MT9T031_MIN_WIDTH 18
#define MT9T031_HORIZONTAL_BLANK 142
#define MT9T031_VERTICAL_BLANK 25
#define MT9T031_COLUMN_SKIP 32
@@ -68,14 +68,21 @@ static const struct soc_camera_data_format mt9t031_colour_formats[] = {
};
struct mt9t031 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
+ struct v4l2_rect rect; /* Sensor window */
int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
- unsigned char autoexposure;
u16 xskip;
u16 yskip;
+ unsigned int gain;
+ unsigned int exposure;
+ unsigned char autoexposure;
};
+static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9t031, subdev);
+}
+
static int reg_read(struct i2c_client *client, const u8 reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
@@ -136,21 +143,10 @@ static int get_shutter(struct i2c_client *client, u32 *data)
return ret < 0 ? ret : 0;
}
-static int mt9t031_init(struct soc_camera_device *icd)
+static int mt9t031_idle(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
int ret;
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
/* Disable chip output, synchronous option update */
ret = reg_write(client, MT9T031_RESET, 1);
if (ret >= 0)
@@ -158,50 +154,39 @@ static int mt9t031_init(struct soc_camera_device *icd)
if (ret >= 0)
ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
- if (ret < 0 && icl->power)
- icl->power(&client->dev, 0);
-
return ret >= 0 ? 0 : -EIO;
}
-static int mt9t031_release(struct soc_camera_device *icd)
+static int mt9t031_disable(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
-
/* Disable the chip */
reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
- if (icl->power)
- icl->power(&client->dev, 0);
-
return 0;
}
-static int mt9t031_start_capture(struct soc_camera_device *icd)
+static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* Switch to master "normal" mode */
- if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
- return -EIO;
- return 0;
-}
+ struct i2c_client *client = sd->priv;
+ int ret;
-static int mt9t031_stop_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
+ if (enable)
+ /* Switch to master "normal" mode */
+ ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2);
+ else
+ /* Stop sensor readout */
+ ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
- /* Stop sensor readout */
- if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
+ if (ret < 0)
return -EIO;
+
return 0;
}
static int mt9t031_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
/* The caller should have queried our parameters, check anyway */
if (flags & ~MT9T031_BUS_PARAM)
@@ -217,69 +202,73 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
- struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
}
-/* Round up minima and round down maxima */
-static void recalculate_limits(struct soc_camera_device *icd,
- u16 xskip, u16 yskip)
+/* target must be _even_ */
+static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
{
- icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
- icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
- icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
- icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
- icd->width_max = MT9T031_MAX_WIDTH / xskip;
- icd->height_max = MT9T031_MAX_HEIGHT / yskip;
+ unsigned int skip;
+
+ if (*source < target + target / 2) {
+ *source = target;
+ return 1;
+ }
+
+ skip = min(max, *source + target / 2) / target;
+ if (skip > 8)
+ skip = 8;
+ *source = target * skip;
+
+ return skip;
}
+/* rect is the sensor rectangle, the caller guarantees parameter validity */
static int mt9t031_set_params(struct soc_camera_device *icd,
struct v4l2_rect *rect, u16 xskip, u16 yskip)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
int ret;
- u16 xbin, ybin, width, height, left, top;
+ u16 xbin, ybin;
const u16 hblank = MT9T031_HORIZONTAL_BLANK,
vblank = MT9T031_VERTICAL_BLANK;
- /* Make sure we don't exceed sensor limits */
- if (rect->left + rect->width > icd->width_max)
- rect->left = (icd->width_max - rect->width) / 2 + icd->x_min;
-
- if (rect->top + rect->height > icd->height_max)
- rect->top = (icd->height_max - rect->height) / 2 + icd->y_min;
-
- width = rect->width * xskip;
- height = rect->height * yskip;
- left = rect->left * xskip;
- top = rect->top * yskip;
-
xbin = min(xskip, (u16)3);
ybin = min(yskip, (u16)3);
- dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n",
- xskip, width, rect->width, yskip, height, rect->height);
-
- /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */
+ /*
+ * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper.
+ * There is always a valid suitably aligned value. The worst case is
+ * xbin = 3, width = 2048. Then we will start at 36, the last read out
+ * pixel will be 2083, which is < 2085 - first black pixel.
+ *
+ * MT9T031 datasheet imposes window left border alignment, depending on
+ * the selected xskip. Failing to conform to this requirement produces
+ * dark horizontal stripes in the image. However, even obeying to this
+ * requirement doesn't eliminate the stripes in all configurations. They
+ * appear "locally reproducibly," but can differ between tests under
+ * different lighting conditions.
+ */
switch (xbin) {
- case 2:
- left = (left + 3) & ~3;
+ case 1:
+ rect->left &= ~1;
break;
- case 3:
- left = roundup(left, 6);
- }
-
- switch (ybin) {
case 2:
- top = (top + 3) & ~3;
+ rect->left &= ~3;
break;
case 3:
- top = roundup(top, 6);
+ rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ?
+ (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6);
}
+ rect->top &= ~1;
+
+ dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n",
+ xskip, yskip, rect->width, rect->height, rect->left, rect->top);
+
/* Disable register update, reconfigure atomically */
ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1);
if (ret < 0)
@@ -299,29 +288,30 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
((ybin - 1) << 4) | (yskip - 1));
}
- dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
+ dev_dbg(&client->dev, "new physical left %u, top %u\n",
+ rect->left, rect->top);
/* The caller provides a supported format, as guaranteed by
* icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
if (ret >= 0)
- ret = reg_write(client, MT9T031_COLUMN_START, left);
+ ret = reg_write(client, MT9T031_COLUMN_START, rect->left);
if (ret >= 0)
- ret = reg_write(client, MT9T031_ROW_START, top);
+ ret = reg_write(client, MT9T031_ROW_START, rect->top);
if (ret >= 0)
- ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1);
+ ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1);
if (ret >= 0)
ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
- height + icd->y_skip_top - 1);
+ rect->height + icd->y_skip_top - 1);
if (ret >= 0 && mt9t031->autoexposure) {
- ret = set_shutter(client, height + icd->y_skip_top + vblank);
+ unsigned int total_h = rect->height + icd->y_skip_top + vblank;
+ ret = set_shutter(client, total_h);
if (ret >= 0) {
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
const struct v4l2_queryctrl *qctrl =
soc_camera_find_qctrl(icd->ops,
V4L2_CID_EXPOSURE);
- icd->exposure = (shutter_max / 2 + (height +
- icd->y_skip_top + vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
}
}
@@ -330,58 +320,99 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
if (ret >= 0)
ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
+ if (ret >= 0) {
+ mt9t031->rect = *rect;
+ mt9t031->xskip = xskip;
+ mt9t031->yskip = yskip;
+ }
+
return ret < 0 ? ret : 0;
}
-static int mt9t031_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct v4l2_rect rect = a->c;
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+
+ rect.width = ALIGN(rect.width, 2);
+ rect.height = ALIGN(rect.height, 2);
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT);
- /* CROP - no change in scaling, or in limits */
- return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
+ return mt9t031_set_params(icd, &rect, mt9t031->xskip, mt9t031->yskip);
}
-static int mt9t031_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
- int ret;
- u16 xskip, yskip;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = f->fmt.pix.width,
- .height = f->fmt.pix.height,
- };
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
- /*
- * try_fmt has put rectangle within limits.
- * S_FMT - use binning and skipping for scaling, recalculate
- * limits, used for cropping
- */
- /* Is this more optimal than just a division? */
- for (xskip = 8; xskip > 1; xskip--)
- if (rect.width * xskip <= MT9T031_MAX_WIDTH)
- break;
+ a->c = mt9t031->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- for (yskip = 8; yskip > 1; yskip--)
- if (rect.height * yskip <= MT9T031_MAX_HEIGHT)
- break;
+ return 0;
+}
- recalculate_limits(icd, xskip, yskip);
+static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9T031_COLUMN_SKIP;
+ a->bounds.top = MT9T031_ROW_SKIP;
+ a->bounds.width = MT9T031_MAX_WIDTH;
+ a->bounds.height = MT9T031_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
- ret = mt9t031_set_params(icd, &rect, xskip, yskip);
- if (!ret) {
- mt9t031->xskip = xskip;
- mt9t031->yskip = yskip;
- }
+ return 0;
+}
- return ret;
+static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = mt9t031->rect.width / mt9t031->xskip;
+ pix->height = mt9t031->rect.height / mt9t031->yskip;
+ pix->pixelformat = V4L2_PIX_FMT_SGRBG10;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ u16 xskip, yskip;
+ struct v4l2_rect rect = mt9t031->rect;
+
+ /*
+ * try_fmt has put width and height within limits.
+ * S_FMT: use binning and skipping for scaling
+ */
+ xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH);
+ yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT);
+
+ /* mt9t031_set_params() doesn't change width and height */
+ return mt9t031_set_params(icd, &rect, xskip, yskip);
}
-static int mt9t031_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+/*
+ * If a user window larger than sensor window is requested, we'll increase the
+ * sensor window.
+ */
+static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -392,15 +423,16 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int mt9t031_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9t031->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9t031->model;
@@ -410,10 +442,10 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9t031_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9t031_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -429,10 +461,10 @@ static int mt9t031_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9t031_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9t031_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -493,39 +525,17 @@ static const struct v4l2_queryctrl mt9t031_controls[] = {
}
};
-static int mt9t031_video_probe(struct soc_camera_device *);
-static void mt9t031_video_remove(struct soc_camera_device *);
-static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *);
-static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *);
-
static struct soc_camera_ops mt9t031_ops = {
- .owner = THIS_MODULE,
- .probe = mt9t031_video_probe,
- .remove = mt9t031_video_remove,
- .init = mt9t031_init,
- .release = mt9t031_release,
- .start_capture = mt9t031_start_capture,
- .stop_capture = mt9t031_stop_capture,
- .set_crop = mt9t031_set_crop,
- .set_fmt = mt9t031_set_fmt,
- .try_fmt = mt9t031_try_fmt,
.set_bus_param = mt9t031_set_bus_param,
.query_bus_param = mt9t031_query_bus_param,
.controls = mt9t031_controls,
.num_controls = ARRAY_SIZE(mt9t031_controls),
- .get_control = mt9t031_get_control,
- .set_control = mt9t031_set_control,
- .get_chip_id = mt9t031_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9t031_get_register,
- .set_register = mt9t031_set_register,
-#endif
};
-static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
int data;
switch (ctrl->id) {
@@ -544,14 +554,21 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9t031->autoexposure;
break;
+ case V4L2_CID_GAIN:
+ ctrl->value = mt9t031->gain;
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = mt9t031->exposure;
+ break;
}
return 0;
}
-static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
const struct v4l2_queryctrl *qctrl;
int data;
@@ -586,7 +603,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long range = qctrl->default_value - qctrl->minimum;
data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
- dev_dbg(&icd->dev, "Setting gain %d\n", data);
+ dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
if (data < 0)
return -EIO;
@@ -606,7 +623,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
/* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
- dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
+ dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n",
reg_read(client, MT9T031_GLOBAL_GAIN), data);
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
if (data < 0)
@@ -614,7 +631,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
}
/* Success */
- icd->gain = ctrl->value;
+ mt9t031->gain = ctrl->value;
break;
case V4L2_CID_EXPOSURE:
/* mt9t031 has maximum == default */
@@ -627,11 +644,11 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
u32 old;
get_shutter(client, &old);
- dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n",
+ dev_dbg(&client->dev, "Set shutter from %u to %u\n",
old, shutter);
if (set_shutter(client, shutter) < 0)
return -EIO;
- icd->exposure = ctrl->value;
+ mt9t031->exposure = ctrl->value;
mt9t031->autoexposure = 0;
}
break;
@@ -639,13 +656,14 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
if (ctrl->value) {
const u16 vblank = MT9T031_VERTICAL_BLANK;
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
- if (set_shutter(client, icd->height +
- icd->y_skip_top + vblank) < 0)
+ unsigned int total_h = mt9t031->rect.height +
+ icd->y_skip_top + vblank;
+
+ if (set_shutter(client, total_h) < 0)
return -EIO;
qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
- icd->exposure = (shutter_max / 2 + (icd->height +
- icd->y_skip_top + vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
mt9t031->autoexposure = 1;
} else
@@ -657,22 +675,16 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
/* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one */
-static int mt9t031_video_probe(struct soc_camera_device *icd)
+static int mt9t031_video_probe(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
s32 data;
int ret;
- /* We must have a parent by now. And it cannot be a wrong one.
- * So this entire test is completely redundant. */
- if (!icd->dev.parent ||
- to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
- return -ENODEV;
-
/* Enable the chip */
data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
- dev_dbg(&icd->dev, "write: %d\n", data);
+ dev_dbg(&client->dev, "write: %d\n", data);
/* Read out the chip version register */
data = reg_read(client, MT9T031_CHIP_VERSION);
@@ -684,44 +696,64 @@ static int mt9t031_video_probe(struct soc_camera_device *icd)
icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
break;
default:
- ret = -ENODEV;
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"No MT9T031 chip detected, register read %x\n", data);
- goto ei2c;
+ return -ENODEV;
}
- dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data);
+ dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
- /* Now that we know the model, we can start video */
- ret = soc_camera_video_start(icd);
- if (ret)
- goto evstart;
+ ret = mt9t031_idle(client);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to initialise the camera\n");
- return 0;
+ /* mt9t031_idle() has reset the chip to default. */
+ mt9t031->exposure = 255;
+ mt9t031->gain = 64;
-evstart:
-ei2c:
return ret;
}
-static void mt9t031_video_remove(struct soc_camera_device *icd)
-{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
+ .g_ctrl = mt9t031_g_ctrl,
+ .s_ctrl = mt9t031_s_ctrl,
+ .g_chip_ident = mt9t031_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9t031_g_register,
+ .s_register = mt9t031_s_register,
+#endif
+};
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
- icd->dev.parent, icd->vdev);
- soc_camera_video_stop(icd);
-}
+static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
+ .s_stream = mt9t031_s_stream,
+ .s_fmt = mt9t031_s_fmt,
+ .g_fmt = mt9t031_g_fmt,
+ .try_fmt = mt9t031_try_fmt,
+ .s_crop = mt9t031_s_crop,
+ .g_crop = mt9t031_g_crop,
+ .cropcap = mt9t031_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9t031_subdev_ops = {
+ .core = &mt9t031_subdev_core_ops,
+ .video = &mt9t031_subdev_video_ops,
+};
static int mt9t031_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9t031 *mt9t031;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9T031: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9T031 driver needs platform data\n");
return -EINVAL;
@@ -737,23 +769,17 @@ static int mt9t031_probe(struct i2c_client *client,
if (!mt9t031)
return -ENOMEM;
- mt9t031->client = client;
- i2c_set_clientdata(client, mt9t031);
+ v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
/* Second stage probe - when a capture adapter is there */
- icd = &mt9t031->icd;
- icd->ops = &mt9t031_ops;
- icd->control = &client->dev;
- icd->x_min = MT9T031_COLUMN_SKIP;
- icd->y_min = MT9T031_ROW_SKIP;
- icd->x_current = icd->x_min;
- icd->y_current = icd->y_min;
- icd->width_min = MT9T031_MIN_WIDTH;
- icd->width_max = MT9T031_MAX_WIDTH;
- icd->height_min = MT9T031_MIN_HEIGHT;
- icd->height_max = MT9T031_MAX_HEIGHT;
- icd->y_skip_top = 0;
- icd->iface = icl->bus_id;
+ icd->ops = &mt9t031_ops;
+ icd->y_skip_top = 0;
+
+ mt9t031->rect.left = MT9T031_COLUMN_SKIP;
+ mt9t031->rect.top = MT9T031_ROW_SKIP;
+ mt9t031->rect.width = MT9T031_MAX_WIDTH;
+ mt9t031->rect.height = MT9T031_MAX_HEIGHT;
+
/* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width */
mt9t031->autoexposure = 1;
@@ -761,24 +787,29 @@ static int mt9t031_probe(struct i2c_client *client,
mt9t031->xskip = 1;
mt9t031->yskip = 1;
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
+ mt9t031_idle(client);
- return 0;
+ ret = mt9t031_video_probe(client);
+
+ mt9t031_disable(client);
+
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9t031);
+ }
-eisdr:
- i2c_set_clientdata(client, NULL);
- kfree(mt9t031);
return ret;
}
static int mt9t031_remove(struct i2c_client *client)
{
- struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&mt9t031->icd);
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9t031);
return 0;
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index dbdcc86ae50d..995607f9d3ba 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -14,13 +14,13 @@
#include <linux/delay.h>
#include <linux/log2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
/* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
- * The platform has to define i2c_board_info
- * and call i2c_register_board_info() */
+ * The platform has to define ctruct i2c_board_info objects and link to them
+ * from struct soc_camera_link */
static char *sensor_type;
module_param(sensor_type, charp, S_IRUGO);
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
#define MT9V022_PIXEL_OPERATION_MODE 0x0f
#define MT9V022_LED_OUT_CONTROL 0x1b
#define MT9V022_ADC_MODE_CONTROL 0x1c
-#define MT9V022_ANALOG_GAIN 0x34
+#define MT9V022_ANALOG_GAIN 0x35
#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
#define MT9V022_PIXCLK_FV_LV 0x74
#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
@@ -55,6 +55,13 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
/* Progressive scan, master, defaults */
#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
+#define MT9V022_MAX_WIDTH 752
+#define MT9V022_MAX_HEIGHT 480
+#define MT9V022_MIN_WIDTH 48
+#define MT9V022_MIN_HEIGHT 32
+#define MT9V022_COLUMN_SKIP 1
+#define MT9V022_ROW_SKIP 4
+
static const struct soc_camera_data_format mt9v022_colour_formats[] = {
/* Order important: first natively supported,
* second supported with a GPIO extender */
@@ -85,12 +92,18 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
};
struct mt9v022 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
+ struct v4l2_rect rect; /* Sensor window */
+ __u32 fourcc;
int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
u16 chip_control;
};
+static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
+}
+
static int reg_read(struct i2c_client *client, const u8 reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
@@ -125,29 +138,11 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
return reg_write(client, reg, ret & ~data);
}
-static int mt9v022_init(struct soc_camera_device *icd)
+static int mt9v022_init(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
int ret;
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
- /*
- * The camera could have been already on, we hard-reset it additionally,
- * if available. Soft reset is done in video_probe().
- */
- if (icl->reset)
- icl->reset(&client->dev);
-
/* Almost the default mode: master, parallel, simultaneous, and an
* undocumented bit 0x200, which is present in table 7, but not in 8,
* plus snapshot mode to disable scan for now */
@@ -161,6 +156,10 @@ static int mt9v022_init(struct soc_camera_device *icd)
/* AEC, AGC on */
ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
if (!ret)
+ ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
+ if (!ret)
+ ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
+ if (!ret)
ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
if (!ret)
/* default - auto */
@@ -171,37 +170,19 @@ static int mt9v022_init(struct soc_camera_device *icd)
return ret;
}
-static int mt9v022_release(struct soc_camera_device *icd)
+static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
-
- if (icl->power)
- icl->power(&mt9v022->client->dev, 0);
-
- return 0;
-}
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
-static int mt9v022_start_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- /* Switch to master "normal" mode */
- mt9v022->chip_control &= ~0x10;
- if (reg_write(client, MT9V022_CHIP_CONTROL,
- mt9v022->chip_control) < 0)
- return -EIO;
- return 0;
-}
+ if (enable)
+ /* Switch to master "normal" mode */
+ mt9v022->chip_control &= ~0x10;
+ else
+ /* Switch to snapshot mode */
+ mt9v022->chip_control |= 0x10;
-static int mt9v022_stop_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- /* Switch to snapshot mode */
- mt9v022->chip_control |= 0x10;
- if (reg_write(client, MT9V022_CHIP_CONTROL,
- mt9v022->chip_control) < 0)
+ if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
return -EIO;
return 0;
}
@@ -209,9 +190,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
static int mt9v022_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
int ret;
u16 pixclk = 0;
@@ -255,7 +236,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
if (ret < 0)
return ret;
- dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+ dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
pixclk, mt9v022->chip_control);
return 0;
@@ -263,8 +244,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned int width_flag;
if (icl->query_bus_param)
@@ -280,60 +260,121 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9v022_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct v4l2_rect rect = a->c;
+ struct soc_camera_device *icd = client->dev.platform_data;
int ret;
+ /* Bayer format - even size lengths */
+ if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 ||
+ mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) {
+ rect.width = ALIGN(rect.width, 2);
+ rect.height = ALIGN(rect.height, 2);
+ /* Let the user play with the starting pixel */
+ }
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
+
/* Like in example app. Contradicts the datasheet though */
ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
if (ret >= 0) {
if (ret & 1) /* Autoexposure */
ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
- rect->height + icd->y_skip_top + 43);
+ rect.height + icd->y_skip_top + 43);
else
ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
- rect->height + icd->y_skip_top + 43);
+ rect.height + icd->y_skip_top + 43);
}
/* Setup frame format: defaults apart from width and height */
if (!ret)
- ret = reg_write(client, MT9V022_COLUMN_START, rect->left);
+ ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
if (!ret)
- ret = reg_write(client, MT9V022_ROW_START, rect->top);
+ ret = reg_write(client, MT9V022_ROW_START, rect.top);
if (!ret)
/* Default 94, Phytec driver says:
* "width + horizontal blank >= 660" */
ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
- rect->width > 660 - 43 ? 43 :
- 660 - rect->width);
+ rect.width > 660 - 43 ? 43 :
+ 660 - rect.width);
if (!ret)
ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
if (!ret)
- ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width);
+ ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
if (!ret)
ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
- rect->height + icd->y_skip_top);
+ rect.height + icd->y_skip_top);
if (ret < 0)
return ret;
- dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
+ dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect.width, rect.height);
+
+ mt9v022->rect = rect;
+
+ return 0;
+}
+
+static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ a->c = mt9v022->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
return 0;
}
-static int mt9v022_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ a->bounds.left = MT9V022_COLUMN_SKIP;
+ a->bounds.top = MT9V022_ROW_SKIP;
+ a->bounds.width = MT9V022_MAX_WIDTH;
+ a->bounds.height = MT9V022_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = pix->width,
- .height = pix->height,
+
+ pix->width = mt9v022->rect.width;
+ pix->height = mt9v022->rect.height;
+ pix->pixelformat = mt9v022->fourcc;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_crop a = {
+ .c = {
+ .left = mt9v022->rect.left,
+ .top = mt9v022->rect.top,
+ .width = pix->width,
+ .height = pix->height,
+ },
};
+ int ret;
/* The caller provides a supported format, as verified per call to
* icd->try_fmt(), datawidth is from our supported format list */
@@ -356,30 +397,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd,
}
/* No support for scaling on this camera, just crop. */
- return mt9v022_set_crop(icd, &rect);
+ ret = mt9v022_s_crop(sd, &a);
+ if (!ret) {
+ pix->width = mt9v022->rect.width;
+ pix->height = mt9v022->rect.height;
+ mt9v022->fourcc = pix->pixelformat;
+ }
+
+ return ret;
}
-static int mt9v022_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
+ struct i2c_client *client = sd->priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
+ int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
+ pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
- v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */,
- &pix->height, 32 + icd->y_skip_top,
- 480 + icd->y_skip_top, 0, 0);
+ v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH,
+ MT9V022_MAX_WIDTH, align,
+ &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top,
+ MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0);
return 0;
}
-static int mt9v022_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9v022->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9v022->model;
@@ -389,10 +442,10 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9v022_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9v022_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -409,10 +462,10 @@ static int mt9v022_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9v022_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9v022_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -481,41 +534,22 @@ static const struct v4l2_queryctrl mt9v022_controls[] = {
}
};
-static int mt9v022_video_probe(struct soc_camera_device *);
-static void mt9v022_video_remove(struct soc_camera_device *);
-static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *);
-static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *);
-
static struct soc_camera_ops mt9v022_ops = {
- .owner = THIS_MODULE,
- .probe = mt9v022_video_probe,
- .remove = mt9v022_video_remove,
- .init = mt9v022_init,
- .release = mt9v022_release,
- .start_capture = mt9v022_start_capture,
- .stop_capture = mt9v022_stop_capture,
- .set_crop = mt9v022_set_crop,
- .set_fmt = mt9v022_set_fmt,
- .try_fmt = mt9v022_try_fmt,
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.controls = mt9v022_controls,
.num_controls = ARRAY_SIZE(mt9v022_controls),
- .get_control = mt9v022_get_control,
- .set_control = mt9v022_set_control,
- .get_chip_id = mt9v022_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9v022_get_register,
- .set_register = mt9v022_set_register,
-#endif
};
-static int mt9v022_get_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
+ const struct v4l2_queryctrl *qctrl;
+ unsigned long range;
int data;
+ qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
+
switch (ctrl->id) {
case V4L2_CID_VFLIP:
data = reg_read(client, MT9V022_READ_MODE);
@@ -541,19 +575,35 @@ static int mt9v022_get_control(struct soc_camera_device *icd,
return -EIO;
ctrl->value = !!(data & 0x2);
break;
+ case V4L2_CID_GAIN:
+ data = reg_read(client, MT9V022_ANALOG_GAIN);
+ if (data < 0)
+ return -EIO;
+
+ range = qctrl->maximum - qctrl->minimum;
+ ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum;
+
+ break;
+ case V4L2_CID_EXPOSURE:
+ data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
+ if (data < 0)
+ return -EIO;
+
+ range = qctrl->maximum - qctrl->minimum;
+ ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum;
+
+ break;
}
return 0;
}
-static int mt9v022_set_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
int data;
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
const struct v4l2_queryctrl *qctrl;
qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
-
if (!qctrl)
return -EINVAL;
@@ -580,12 +630,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
return -EINVAL;
else {
unsigned long range = qctrl->maximum - qctrl->minimum;
- /* Datasheet says 16 to 64. autogain only works properly
- * after setting gain to maximum 14. Larger values
- * produce "white fly" noise effect. On the whole,
- * manually setting analog gain does no good. */
+ /* Valid values 16 to 64, 32 to 64 must be even. */
unsigned long gain = ((ctrl->value - qctrl->minimum) *
- 10 + range / 2) / range + 4;
+ 48 + range / 2) / range + 16;
if (gain >= 32)
gain &= ~1;
/* The user wants to set gain manually, hope, she
@@ -594,11 +641,10 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
return -EIO;
- dev_info(&icd->dev, "Setting gain from %d to %lu\n",
- reg_read(client, MT9V022_ANALOG_GAIN), gain);
+ dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
+ reg_read(client, MT9V022_ANALOG_GAIN), gain);
if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0)
return -EIO;
- icd->gain = ctrl->value;
}
break;
case V4L2_CID_EXPOSURE:
@@ -615,13 +661,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
return -EIO;
- dev_dbg(&icd->dev, "Shutter width from %d to %lu\n",
+ dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
shutter);
if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
shutter) < 0)
return -EIO;
- icd->exposure = ctrl->value;
}
break;
case V4L2_CID_AUTOGAIN:
@@ -646,11 +691,11 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
/* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one */
-static int mt9v022_video_probe(struct soc_camera_device *icd)
+static int mt9v022_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
s32 data;
int ret;
unsigned long flags;
@@ -665,7 +710,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
/* must be 0x1311 or 0x1313 */
if (data != 0x1311 && data != 0x1313) {
ret = -ENODEV;
- dev_info(&icd->dev, "No MT9V022 detected, ID register 0x%x\n",
+ dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
data);
goto ei2c;
}
@@ -677,7 +722,9 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
/* 15 clock cycles */
udelay(200);
if (reg_read(client, MT9V022_RESET)) {
- dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
+ dev_err(&client->dev, "Resetting MT9V022 failed!\n");
+ if (ret > 0)
+ ret = -EIO;
goto ei2c;
}
@@ -694,7 +741,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
}
if (ret < 0)
- goto eisis;
+ goto ei2c;
icd->num_formats = 0;
@@ -716,42 +763,70 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
if (flags & SOCAM_DATAWIDTH_8)
icd->num_formats++;
- ret = soc_camera_video_start(icd);
- if (ret < 0)
- goto eisis;
+ mt9v022->fourcc = icd->formats->fourcc;
- dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+ dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
"monochrome" : "colour");
- return 0;
+ ret = mt9v022_init(client);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to initialise the camera\n");
-eisis:
ei2c:
return ret;
}
static void mt9v022_video_remove(struct soc_camera_device *icd)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
+ dev_dbg(&icd->dev, "Video removed: %p, %p\n",
icd->dev.parent, icd->vdev);
- soc_camera_video_stop(icd);
if (icl->free_bus)
icl->free_bus(icl);
}
+static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
+ .g_ctrl = mt9v022_g_ctrl,
+ .s_ctrl = mt9v022_s_ctrl,
+ .g_chip_ident = mt9v022_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9v022_g_register,
+ .s_register = mt9v022_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
+ .s_stream = mt9v022_s_stream,
+ .s_fmt = mt9v022_s_fmt,
+ .g_fmt = mt9v022_g_fmt,
+ .try_fmt = mt9v022_try_fmt,
+ .s_crop = mt9v022_s_crop,
+ .g_crop = mt9v022_g_crop,
+ .cropcap = mt9v022_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9v022_subdev_ops = {
+ .core = &mt9v022_subdev_core_ops,
+ .video = &mt9v022_subdev_video_ops,
+};
+
static int mt9v022_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9v022 *mt9v022;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9V022: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9V022 driver needs platform data\n");
return -EINVAL;
@@ -767,40 +842,41 @@ static int mt9v022_probe(struct i2c_client *client,
if (!mt9v022)
return -ENOMEM;
+ v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
+
mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
- mt9v022->client = client;
- i2c_set_clientdata(client, mt9v022);
-
- icd = &mt9v022->icd;
- icd->ops = &mt9v022_ops;
- icd->control = &client->dev;
- icd->x_min = 1;
- icd->y_min = 4;
- icd->x_current = 1;
- icd->y_current = 4;
- icd->width_min = 48;
- icd->width_max = 752;
- icd->height_min = 32;
- icd->height_max = 480;
- icd->y_skip_top = 1;
- icd->iface = icl->bus_id;
-
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
- return 0;
+ icd->ops = &mt9v022_ops;
+ /*
+ * MT9V022 _really_ corrupts the first read out line.
+ * TODO: verify on i.MX31
+ */
+ icd->y_skip_top = 1;
+
+ mt9v022->rect.left = MT9V022_COLUMN_SKIP;
+ mt9v022->rect.top = MT9V022_ROW_SKIP;
+ mt9v022->rect.width = MT9V022_MAX_WIDTH;
+ mt9v022->rect.height = MT9V022_MAX_HEIGHT;
+
+ ret = mt9v022_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9v022);
+ }
-eisdr:
- kfree(mt9v022);
return ret;
}
static int mt9v022_remove(struct i2c_client *client)
{
- struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&mt9v022->icd);
+ icd->ops = NULL;
+ mt9v022_video_remove(icd);
+ i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9v022);
return 0;
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 736c31d23194..5f37952c75cf 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -126,7 +126,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
{
struct soc_camera_device *icd = vq->priv_data;
- *size = icd->width * icd->height *
+ *size = icd->user_width * icd->user_height *
((icd->current_fmt->depth + 7) >> 3);
if (!*count)
@@ -135,7 +135,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
while (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
(*count)--;
- dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+ dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
return 0;
}
@@ -147,7 +147,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
BUG_ON(in_interrupt());
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/* This waits until this buffer is out of danger, i.e., until it is no
@@ -165,7 +165,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
int ret;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/* Added list head initialization on alloc */
@@ -178,12 +178,12 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
buf->inwork = 1;
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -216,10 +216,11 @@ out:
static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
{
struct videobuf_buffer *vbuf = &pcdev->active->vb;
+ struct device *dev = pcdev->icd->dev.parent;
int ret;
if (unlikely(!pcdev->active)) {
- dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
+ dev_err(dev, "DMA End IRQ with no active buffer\n");
return -EFAULT;
}
@@ -229,7 +230,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
vbuf->size, pcdev->res->start +
CSIRXR, DMA_MODE_READ);
if (unlikely(ret))
- dev_err(pcdev->soc_host.dev, "Failed to setup DMA sg list\n");
+ dev_err(dev, "Failed to setup DMA sg list\n");
return ret;
}
@@ -243,7 +244,7 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq,
struct mx1_camera_dev *pcdev = ici->priv;
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
list_add_tail(&vb->queue, &pcdev->capture);
@@ -270,22 +271,23 @@ static void mx1_videobuf_release(struct videobuf_queue *vq,
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
#ifdef DEBUG
struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
switch (vb->state) {
case VIDEOBUF_ACTIVE:
- dev_dbg(&icd->dev, "%s (active)\n", __func__);
+ dev_dbg(dev, "%s (active)\n", __func__);
break;
case VIDEOBUF_QUEUED:
- dev_dbg(&icd->dev, "%s (queued)\n", __func__);
+ dev_dbg(dev, "%s (queued)\n", __func__);
break;
case VIDEOBUF_PREPARED:
- dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
+ dev_dbg(dev, "%s (prepared)\n", __func__);
break;
default:
- dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
+ dev_dbg(dev, "%s (unknown)\n", __func__);
break;
}
#endif
@@ -325,6 +327,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
static void mx1_camera_dma_irq(int channel, void *data)
{
struct mx1_camera_dev *pcdev = data;
+ struct device *dev = pcdev->icd->dev.parent;
struct mx1_buffer *buf;
struct videobuf_buffer *vb;
unsigned long flags;
@@ -334,14 +337,14 @@ static void mx1_camera_dma_irq(int channel, void *data)
imx_dma_disable(channel);
if (unlikely(!pcdev->active)) {
- dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
+ dev_err(dev, "DMA End IRQ with no active buffer\n");
goto out;
}
vb = &pcdev->active->vb;
buf = container_of(vb, struct mx1_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));
- dev_dbg(pcdev->soc_host.dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
mx1_camera_wakeup(pcdev, vb, buf);
@@ -362,7 +365,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx1_camera_dev *pcdev = ici->priv;
- videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, ici->dev,
+ videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent,
&pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
@@ -381,8 +384,9 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
* they get a nice Oops */
div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
- dev_dbg(pcdev->soc_host.dev, "System clock %lukHz, target freq %dkHz, "
- "divisor %lu\n", lcdclk / 1000, mclk / 1000, div);
+ dev_dbg(pcdev->icd->dev.parent,
+ "System clock %lukHz, target freq %dkHz, divisor %lu\n",
+ lcdclk / 1000, mclk / 1000, div);
return div;
}
@@ -391,7 +395,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
{
unsigned int csicr1 = CSICR1_EN;
- dev_dbg(pcdev->soc_host.dev, "Activate device\n");
+ dev_dbg(pcdev->icd->dev.parent, "Activate device\n");
clk_enable(pcdev->clk);
@@ -407,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
{
- dev_dbg(pcdev->soc_host.dev, "Deactivate device\n");
+ dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n");
/* Disable all CSI interface */
__raw_writel(0x00, pcdev->base + CSICR1);
@@ -428,14 +432,12 @@ static int mx1_camera_add_device(struct soc_camera_device *icd)
goto ebusy;
}
- dev_info(&icd->dev, "MX1 Camera driver attached to camera %d\n",
+ dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n",
icd->devnum);
mx1_camera_activate(pcdev);
- ret = icd->ops->init(icd);
- if (!ret)
- pcdev->icd = icd;
+ pcdev->icd = icd;
ebusy:
return ret;
@@ -456,20 +458,20 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
/* Stop DMA engine */
imx_dma_disable(pcdev->dma_chan);
- dev_info(&icd->dev, "MX1 Camera driver detached from camera %d\n",
+ dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n",
icd->devnum);
- icd->ops->release(icd);
-
mx1_camera_deactivate(pcdev);
pcdev->icd = NULL;
}
static int mx1_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
- return icd->ops->set_crop(icd, rect);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, video, s_crop, a);
}
static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
@@ -539,18 +541,19 @@ static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
static int mx1_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
+ dev_warn(icd->dev.parent, "Format %x not found\n",
+ pix->pixelformat);
return -EINVAL;
}
- ret = icd->ops->set_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
@@ -562,10 +565,11 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
static int mx1_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
/* TODO: limit to mx1 hardware capabilities */
/* limit to sensor capabilities */
- return icd->ops->try_fmt(icd, f);
+ return v4l2_subdev_call(sd, video, try_fmt, f);
}
static int mx1_camera_reqbufs(struct soc_camera_file *icf,
@@ -737,7 +741,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
pcdev->soc_host.drv_name = DRIVER_NAME;
pcdev->soc_host.ops = &mx1_soc_camera_host_ops;
pcdev->soc_host.priv = pcdev;
- pcdev->soc_host.dev = &pdev->dev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
err = soc_camera_host_register(&pcdev->soc_host);
if (err)
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 9770cb7932ca..dff2e5e2d8c6 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -178,7 +178,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf
BUG_ON(in_interrupt());
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/*
@@ -220,7 +220,7 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
if (!mx3_cam->idmac_channel[0])
return -EINVAL;
- *size = icd->width * icd->height * bpp;
+ *size = icd->user_width * icd->user_height * bpp;
if (!*count)
*count = 32;
@@ -241,7 +241,7 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
struct mx3_camera_buffer *buf =
container_of(vb, struct mx3_camera_buffer, vb);
/* current_fmt _must_ always be set */
- size_t new_size = icd->width * icd->height *
+ size_t new_size = icd->user_width * icd->user_height *
((icd->current_fmt->depth + 7) >> 3);
int ret;
@@ -251,12 +251,12 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
*/
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
if (vb->state != VIDEOBUF_NEEDS_INIT)
free_buffer(vq, buf);
@@ -354,9 +354,9 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
/* This is the configuration of one sg-element */
video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc);
- video->out_width = icd->width;
- video->out_height = icd->height;
- video->out_stride = icd->width;
+ video->out_width = icd->user_width;
+ video->out_height = icd->user_height;
+ video->out_stride = icd->user_width;
#ifdef DEBUG
/* helps to see what DMA actually has written */
@@ -375,7 +375,8 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
spin_unlock_irq(&mx3_cam->lock);
cookie = txd->tx_submit(txd);
- dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg));
+ dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n",
+ cookie, sg_dma_address(&buf->sg));
spin_lock_irq(&mx3_cam->lock);
@@ -402,9 +403,10 @@ static void mx3_videobuf_release(struct videobuf_queue *vq,
container_of(vb, struct mx3_camera_buffer, vb);
unsigned long flags;
- dev_dbg(&icd->dev, "Release%s DMA 0x%08x (state %d), queue %sempty\n",
+ dev_dbg(icd->dev.parent,
+ "Release%s DMA 0x%08x (state %d), queue %sempty\n",
mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
- vb->state, list_empty(&vb->queue) ? "" : "not ");
+ vb->state, list_empty(&vb->queue) ? "" : "not ");
spin_lock_irqsave(&mx3_cam->lock, flags);
if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
!list_empty(&vb->queue)) {
@@ -431,7 +433,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
- videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, ici->dev,
+ videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, icd->dev.parent,
&mx3_cam->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
@@ -484,7 +486,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
clk_enable(mx3_cam->clk);
rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
- dev_dbg(&icd->dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+ dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
if (rate)
clk_set_rate(mx3_cam->clk, rate);
}
@@ -494,29 +496,18 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
- int ret;
- if (mx3_cam->icd) {
- ret = -EBUSY;
- goto ebusy;
- }
+ if (mx3_cam->icd)
+ return -EBUSY;
mx3_camera_activate(mx3_cam, icd);
- ret = icd->ops->init(icd);
- if (ret < 0) {
- clk_disable(mx3_cam->clk);
- goto einit;
- }
mx3_cam->icd = icd;
-einit:
-ebusy:
- if (!ret)
- dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
- icd->devnum);
+ dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n",
+ icd->devnum);
- return ret;
+ return 0;
}
/* Called with .video_lock held */
@@ -533,13 +524,11 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd)
*ichan = NULL;
}
- icd->ops->release(icd);
-
clk_disable(mx3_cam->clk);
mx3_cam->icd = NULL;
- dev_info(&icd->dev, "MX3 Camera driver detached from camera %d\n",
+ dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n",
icd->devnum);
}
@@ -551,7 +540,8 @@ static bool channel_change_requested(struct soc_camera_device *icd,
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
/* Do buffers have to be re-allocated or channel re-configured? */
- return ichan && rect->width * rect->height > icd->width * icd->height;
+ return ichan && rect->width * rect->height >
+ icd->user_width * icd->user_height;
}
static int test_platform_param(struct mx3_camera_dev *mx3_cam,
@@ -599,8 +589,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
*flags |= SOCAM_DATAWIDTH_4;
break;
default:
- dev_info(mx3_cam->soc_host.dev, "Unsupported bus width %d\n",
- buswidth);
+ dev_warn(mx3_cam->soc_host.v4l2_dev.dev,
+ "Unsupported bus width %d\n", buswidth);
return -EINVAL;
}
@@ -615,7 +605,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
unsigned long bus_flags, camera_flags;
int ret = test_platform_param(mx3_cam, depth, &bus_flags);
- dev_dbg(ici->dev, "requested bus width %d bit: %d\n", depth, ret);
+ dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret);
if (ret < 0)
return ret;
@@ -624,7 +614,8 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
ret = soc_camera_bus_param_compatible(camera_flags, bus_flags);
if (ret < 0)
- dev_warn(&icd->dev, "Flags incompatible: camera %lx, host %lx\n",
+ dev_warn(icd->dev.parent,
+ "Flags incompatible: camera %lx, host %lx\n",
camera_flags, bus_flags);
return ret;
@@ -638,7 +629,7 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
if (!rq)
return false;
- pdata = rq->mx3_cam->soc_host.dev->platform_data;
+ pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data;
return rq->id == chan->chan_id &&
pdata->dma_dev == chan->device->dev;
@@ -698,7 +689,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(icd->dev.parent,
+ "Providing format %s using %s\n",
mx3_camera_formats[0].name,
icd->formats[idx].name);
}
@@ -710,7 +702,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(icd->dev.parent,
+ "Providing format %s using %s\n",
mx3_camera_formats[0].name,
icd->formats[idx].name);
}
@@ -723,7 +716,7 @@ passthrough:
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev,
+ dev_dbg(icd->dev.parent,
"Providing format %s in pass-through mode\n",
icd->formats[idx].name);
}
@@ -733,13 +726,13 @@ passthrough:
}
static void configure_geometry(struct mx3_camera_dev *mx3_cam,
- struct v4l2_rect *rect)
+ unsigned int width, unsigned int height)
{
u32 ctrl, width_field, height_field;
/* Setup frame size - this cannot be changed on-the-fly... */
- width_field = rect->width - 1;
- height_field = rect->height - 1;
+ width_field = width - 1;
+ height_field = height - 1;
csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
@@ -751,11 +744,6 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam,
ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
/* Sensor does the cropping */
csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
-
- /*
- * No need to free resources here if we fail, we'll see if we need to
- * do this next time we are called
- */
}
static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
@@ -792,25 +780,74 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
return 0;
}
+/*
+ * FIXME: learn to use stride != width, then we can keep stride properly aligned
+ * and support arbitrary (even) widths.
+ */
+static inline void stride_align(__s32 *width)
+{
+ if (((*width + 7) & ~7) < 4096)
+ *width = (*width + 7) & ~7;
+ else
+ *width = *width & ~7;
+}
+
+/*
+ * As long as we don't implement host-side cropping and scaling, we can use
+ * default g_crop and cropcap from soc_camera.c
+ */
static int mx3_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
+ struct v4l2_rect *rect = &a->c;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
+ struct v4l2_pix_format *pix = &f.fmt.pix;
+ int ret;
- /*
- * We now know pixel formats and can decide upon DMA-channel(s)
- * So far only direct camera-to-memory is supported
- */
- if (channel_change_requested(icd, rect)) {
- int ret = acquire_dma_channel(mx3_cam);
+ soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+ soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+ ret = v4l2_subdev_call(sd, video, s_crop, a);
+ if (ret < 0)
+ return ret;
+
+ /* The capture device might have changed its output */
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ if (pix->width & 7) {
+ /* Ouch! We can only handle 8-byte aligned width... */
+ stride_align(&pix->width);
+ ret = v4l2_subdev_call(sd, video, s_fmt, &f);
if (ret < 0)
return ret;
}
- configure_geometry(mx3_cam, rect);
+ if (pix->width != icd->user_width || pix->height != icd->user_height) {
+ /*
+ * We now know pixel formats and can decide upon DMA-channel(s)
+ * So far only direct camera-to-memory is supported
+ */
+ if (channel_change_requested(icd, rect)) {
+ int ret = acquire_dma_channel(mx3_cam);
+ if (ret < 0)
+ return ret;
+ }
+
+ configure_geometry(mx3_cam, pix->width, pix->height);
+ }
+
+ dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+ pix->width, pix->height);
- return icd->ops->set_crop(icd, rect);
+ icd->user_width = pix->width;
+ icd->user_height = pix->height;
+
+ return ret;
}
static int mx3_camera_set_fmt(struct soc_camera_device *icd,
@@ -818,22 +855,21 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = pix->width,
- .height = pix->height,
- };
int ret;
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
+ dev_warn(icd->dev.parent, "Format %x not found\n",
+ pix->pixelformat);
return -EINVAL;
}
+ stride_align(&pix->width);
+ dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height);
+
ret = acquire_dma_channel(mx3_cam);
if (ret < 0)
return ret;
@@ -844,21 +880,23 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
* mxc_v4l2_s_fmt()
*/
- configure_geometry(mx3_cam, &rect);
+ configure_geometry(mx3_cam, pix->width, pix->height);
- ret = icd->ops->set_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
}
+ dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height);
+
return ret;
}
static int mx3_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
__u32 pixfmt = pix->pixelformat;
@@ -867,7 +905,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (pixfmt && !xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
return -EINVAL;
}
@@ -884,7 +922,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
/* camera has to see its format, but the user the original one */
pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- ret = icd->ops->try_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
pix->pixelformat = xlate->host_fmt->fourcc;
field = pix->field;
@@ -892,7 +930,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
if (field == V4L2_FIELD_ANY) {
pix->field = V4L2_FIELD_NONE;
} else if (field != V4L2_FIELD_NONE) {
- dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+ dev_err(icd->dev.parent, "Field type %d unsupported.\n", field);
return -EINVAL;
}
@@ -931,14 +969,15 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
u32 dw, sens_conf;
int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags);
const struct soc_camera_format_xlate *xlate;
+ struct device *dev = icd->dev.parent;
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
- dev_dbg(ici->dev, "requested bus width %d bit: %d\n",
+ dev_dbg(dev, "requested bus width %d bit: %d\n",
icd->buswidth, ret);
if (ret < 0)
@@ -947,9 +986,10 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
+ camera_flags, bus_flags, common_flags);
if (!common_flags) {
- dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n",
- camera_flags, bus_flags);
+ dev_dbg(dev, "no common flags");
return -EINVAL;
}
@@ -1002,8 +1042,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
SOCAM_DATAWIDTH_4;
ret = icd->ops->set_bus_param(icd, common_flags);
- if (ret < 0)
+ if (ret < 0) {
+ dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n",
+ common_flags, ret);
return ret;
+ }
/*
* So far only gated clock mode is supported. Add a line
@@ -1055,7 +1098,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
- dev_dbg(ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+ dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw);
return 0;
}
@@ -1127,8 +1170,9 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mx3_cam->capture);
spin_lock_init(&mx3_cam->lock);
- base = ioremap(res->start, res->end - res->start + 1);
+ base = ioremap(res->start, resource_size(res));
if (!base) {
+ pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
err = -ENOMEM;
goto eioremap;
}
@@ -1139,7 +1183,7 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
soc_host->drv_name = MX3_CAM_DRV_NAME;
soc_host->ops = &mx3_soc_camera_host_ops;
soc_host->priv = mx3_cam;
- soc_host->dev = &pdev->dev;
+ soc_host->v4l2_dev.dev = &pdev->dev;
soc_host->nr = pdev->id;
err = soc_camera_host_register(soc_host);
@@ -1215,3 +1259,4 @@ module_exit(mx3_camera_exit);
MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 0bce255168bd..eccb40ab7fec 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -22,7 +22,7 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
#include <media/ov772x.h>
@@ -382,11 +382,10 @@ struct regval_list {
};
struct ov772x_color_format {
- char *name;
- __u32 fourcc;
- u8 dsp3;
- u8 com3;
- u8 com7;
+ const struct soc_camera_data_format *format;
+ u8 dsp3;
+ u8 com3;
+ u8 com7;
};
struct ov772x_win_size {
@@ -398,14 +397,15 @@ struct ov772x_win_size {
};
struct ov772x_priv {
+ struct v4l2_subdev subdev;
struct ov772x_camera_info *info;
- struct i2c_client *client;
- struct soc_camera_device icd;
const struct ov772x_color_format *fmt;
const struct ov772x_win_size *win;
int model;
- unsigned int flag_vflip:1;
- unsigned int flag_hflip:1;
+ unsigned short flag_vflip:1;
+ unsigned short flag_hflip:1;
+ /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
+ unsigned short band_filter;
};
#define ENDMARKER { 0xff, 0xff }
@@ -481,43 +481,43 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = {
*/
static const struct ov772x_color_format ov772x_cfmts[] = {
{
- SETFOURCC(YUYV),
+ .format = &ov772x_fmt_lists[0],
.dsp3 = 0x0,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- SETFOURCC(YVYU),
+ .format = &ov772x_fmt_lists[1],
.dsp3 = UV_ON,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- SETFOURCC(UYVY),
+ .format = &ov772x_fmt_lists[2],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = OFMT_YUV,
},
{
- SETFOURCC(RGB555),
+ .format = &ov772x_fmt_lists[3],
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
- SETFOURCC(RGB555X),
+ .format = &ov772x_fmt_lists[4],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
- SETFOURCC(RGB565),
+ .format = &ov772x_fmt_lists[5],
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB565 | OFMT_RGB,
},
{
- SETFOURCC(RGB565X),
+ .format = &ov772x_fmt_lists[6],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB565 | OFMT_RGB,
@@ -570,6 +570,15 @@ static const struct v4l2_queryctrl ov772x_controls[] = {
.step = 1,
.default_value = 0,
},
+ {
+ .id = V4L2_CID_BAND_STOP_FILTER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Band-stop filter",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
};
@@ -577,6 +586,12 @@ static const struct v4l2_queryctrl ov772x_controls[] = {
* general function
*/
+static struct ov772x_priv *to_ov772x(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov772x_priv,
+ subdev);
+}
+
static int ov772x_write_array(struct i2c_client *client,
const struct regval_list *vals)
{
@@ -617,58 +632,29 @@ static int ov772x_reset(struct i2c_client *client)
* soc_camera_ops function
*/
-static int ov772x_init(struct soc_camera_device *icd)
+static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- int ret = 0;
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
- if (priv->info->link.power) {
- ret = priv->info->link.power(&priv->client->dev, 1);
- if (ret < 0)
- return ret;
+ if (!enable) {
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+ return 0;
}
- if (priv->info->link.reset)
- ret = priv->info->link.reset(&priv->client->dev);
-
- return ret;
-}
-
-static int ov772x_release(struct soc_camera_device *icd)
-{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- int ret = 0;
-
- if (priv->info->link.power)
- ret = priv->info->link.power(&priv->client->dev, 0);
-
- return ret;
-}
-
-static int ov772x_start_capture(struct soc_camera_device *icd)
-{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-
if (!priv->win || !priv->fmt) {
- dev_err(&icd->dev, "norm or win select error\n");
+ dev_err(&client->dev, "norm or win select error\n");
return -EPERM;
}
- ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0);
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
- dev_dbg(&icd->dev,
- "format %s, win %s\n", priv->fmt->name, priv->win->name);
+ dev_dbg(&client->dev, "format %s, win %s\n",
+ priv->fmt->format->name, priv->win->name);
return 0;
}
-static int ov772x_stop_capture(struct soc_camera_device *icd)
-{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
- return 0;
-}
-
static int ov772x_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
@@ -677,8 +663,9 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd,
static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- struct soc_camera_link *icl = &priv->info->link;
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct ov772x_priv *priv = i2c_get_clientdata(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
@@ -686,10 +673,10 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
return soc_camera_apply_sensor_flags(icl, flags);
}
-static int ov772x_get_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
@@ -698,14 +685,17 @@ static int ov772x_get_control(struct soc_camera_device *icd,
case V4L2_CID_HFLIP:
ctrl->value = priv->flag_hflip;
break;
+ case V4L2_CID_BAND_STOP_FILTER:
+ ctrl->value = priv->band_filter;
+ break;
}
return 0;
}
-static int ov772x_set_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
int ret = 0;
u8 val;
@@ -715,24 +705,48 @@ static int ov772x_set_control(struct soc_camera_device *icd,
priv->flag_vflip = ctrl->value;
if (priv->info->flags & OV772X_FLAG_VFLIP)
val ^= VFLIP_IMG;
- ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val);
+ ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val);
break;
case V4L2_CID_HFLIP:
val = ctrl->value ? HFLIP_IMG : 0x00;
priv->flag_hflip = ctrl->value;
if (priv->info->flags & OV772X_FLAG_HFLIP)
val ^= HFLIP_IMG;
- ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val);
+ ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val);
+ break;
+ case V4L2_CID_BAND_STOP_FILTER:
+ if ((unsigned)ctrl->value > 256)
+ ctrl->value = 256;
+ if (ctrl->value == priv->band_filter)
+ break;
+ if (!ctrl->value) {
+ /* Switch the filter off, it is on now */
+ ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
+ if (!ret)
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, 0);
+ } else {
+ /* Switch the filter on, set AEC low limit */
+ val = 256 - ctrl->value;
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, BNDF_ON_OFF);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, val);
+ }
+ if (!ret)
+ priv->band_filter = ctrl->value;
break;
}
return ret;
}
-static int ov772x_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
id->ident = priv->model;
id->revision = 0;
@@ -741,17 +755,17 @@ static int ov772x_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov772x_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int ov772x_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- int ret;
+ struct i2c_client *client = sd->priv;
+ int ret;
reg->size = 1;
if (reg->reg > 0xff)
return -EINVAL;
- ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
if (ret < 0)
return ret;
@@ -760,21 +774,20 @@ static int ov772x_get_register(struct soc_camera_device *icd,
return 0;
}
-static int ov772x_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int ov772x_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
if (reg->reg > 0xff ||
reg->val > 0xff)
return -EINVAL;
- return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
}
#endif
-static const struct ov772x_win_size*
-ov772x_select_win(u32 width, u32 height)
+static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
{
__u32 diff;
const struct ov772x_win_size *win;
@@ -793,9 +806,10 @@ ov772x_select_win(u32 width, u32 height)
return win;
}
-static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
- u32 pixfmt)
+static int ov772x_set_params(struct i2c_client *client,
+ u32 *width, u32 *height, u32 pixfmt)
{
+ struct ov772x_priv *priv = to_ov772x(client);
int ret = -EINVAL;
u8 val;
int i;
@@ -805,7 +819,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
*/
priv->fmt = NULL;
for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
- if (pixfmt == ov772x_cfmts[i].fourcc) {
+ if (pixfmt == ov772x_cfmts[i].format->fourcc) {
priv->fmt = ov772x_cfmts + i;
break;
}
@@ -816,12 +830,12 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
/*
* select win
*/
- priv->win = ov772x_select_win(width, height);
+ priv->win = ov772x_select_win(*width, *height);
/*
* reset hardware
*/
- ov772x_reset(priv->client);
+ ov772x_reset(client);
/*
* Edge Ctrl
@@ -835,17 +849,17 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
* Remove it when manual mode.
*/
- ret = ov772x_mask_set(priv->client, DSPAUTO, EDGE_ACTRL, 0x00);
+ ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_TRSHLD, EDGE_THRESHOLD_MASK,
priv->info->edgectrl.threshold);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_STRNGT, EDGE_STRENGTH_MASK,
priv->info->edgectrl.strength);
if (ret < 0)
@@ -857,13 +871,13 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
*
* set upper and lower limit
*/
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_UPPER, EDGE_UPPER_MASK,
priv->info->edgectrl.upper);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_LOWER, EDGE_LOWER_MASK,
priv->info->edgectrl.lower);
if (ret < 0)
@@ -873,7 +887,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
/*
* set size format
*/
- ret = ov772x_write_array(priv->client, priv->win->regs);
+ ret = ov772x_write_array(client, priv->win->regs);
if (ret < 0)
goto ov772x_set_fmt_error;
@@ -882,7 +896,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
*/
val = priv->fmt->dsp3;
if (val) {
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
DSP_CTRL3, UV_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
@@ -901,7 +915,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
if (priv->flag_hflip)
val ^= HFLIP_IMG;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
COM3, SWAP_MASK | IMG_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
@@ -910,47 +924,99 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
* set COM7
*/
val = priv->win->com7_bit | priv->fmt->com7;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
val);
if (ret < 0)
goto ov772x_set_fmt_error;
+ /*
+ * set COM8
+ */
+ if (priv->band_filter) {
+ ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, 256 - priv->band_filter);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ *width = priv->win->width;
+ *height = priv->win->height;
+
return ret;
ov772x_set_fmt_error:
- ov772x_reset(priv->client);
+ ov772x_reset(client);
priv->win = NULL;
priv->fmt = NULL;
return ret;
}
-static int ov772x_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = VGA_WIDTH;
+ a->c.height = VGA_HEIGHT;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (!priv->fmt)
- return -EINVAL;
+ return 0;
+}
- return ov772x_set_params(priv, rect->width, rect->height,
- priv->fmt->fourcc);
+static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = VGA_WIDTH;
+ a->bounds.height = VGA_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
}
-static int ov772x_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (!priv->win || !priv->fmt) {
+ u32 width = VGA_WIDTH, height = VGA_HEIGHT;
+ int ret = ov772x_set_params(client, &width, &height,
+ V4L2_PIX_FMT_YUYV);
+ if (ret < 0)
+ return ret;
+ }
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ pix->width = priv->win->width;
+ pix->height = priv->win->height;
+ pix->pixelformat = priv->fmt->format->fourcc;
+ pix->colorspace = priv->fmt->format->colorspace;
+ pix->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
struct v4l2_pix_format *pix = &f->fmt.pix;
- return ov772x_set_params(priv, pix->width, pix->height,
+ return ov772x_set_params(client, &pix->width, &pix->height,
pix->pixelformat);
}
-static int ov772x_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int ov772x_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
const struct ov772x_win_size *win;
@@ -967,9 +1033,10 @@ static int ov772x_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int ov772x_video_probe(struct soc_camera_device *icd)
+static int ov772x_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct ov772x_priv *priv = to_ov772x(client);
u8 pid, ver;
const char *devname;
@@ -986,7 +1053,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
*/
if (SOCAM_DATAWIDTH_10 != priv->info->buswidth &&
SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
- dev_err(&icd->dev, "bus width error\n");
+ dev_err(&client->dev, "bus width error\n");
return -ENODEV;
}
@@ -996,8 +1063,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
/*
* check and show product ID and manufacturer ID
*/
- pid = i2c_smbus_read_byte_data(priv->client, PID);
- ver = i2c_smbus_read_byte_data(priv->client, VER);
+ pid = i2c_smbus_read_byte_data(client, PID);
+ ver = i2c_smbus_read_byte_data(client, VER);
switch (VERSION(pid, ver)) {
case OV7720:
@@ -1009,69 +1076,77 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
priv->model = V4L2_IDENT_OV7725;
break;
default:
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"Product ID error %x:%x\n", pid, ver);
return -ENODEV;
}
- dev_info(&icd->dev,
+ dev_info(&client->dev,
"%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
devname,
pid,
ver,
- i2c_smbus_read_byte_data(priv->client, MIDH),
- i2c_smbus_read_byte_data(priv->client, MIDL));
-
- return soc_camera_video_start(icd);
-}
+ i2c_smbus_read_byte_data(client, MIDH),
+ i2c_smbus_read_byte_data(client, MIDL));
-static void ov772x_video_remove(struct soc_camera_device *icd)
-{
- soc_camera_video_stop(icd);
+ return 0;
}
static struct soc_camera_ops ov772x_ops = {
- .owner = THIS_MODULE,
- .probe = ov772x_video_probe,
- .remove = ov772x_video_remove,
- .init = ov772x_init,
- .release = ov772x_release,
- .start_capture = ov772x_start_capture,
- .stop_capture = ov772x_stop_capture,
- .set_crop = ov772x_set_crop,
- .set_fmt = ov772x_set_fmt,
- .try_fmt = ov772x_try_fmt,
.set_bus_param = ov772x_set_bus_param,
.query_bus_param = ov772x_query_bus_param,
.controls = ov772x_controls,
.num_controls = ARRAY_SIZE(ov772x_controls),
- .get_control = ov772x_get_control,
- .set_control = ov772x_set_control,
- .get_chip_id = ov772x_get_chip_id,
+};
+
+static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
+ .g_ctrl = ov772x_g_ctrl,
+ .s_ctrl = ov772x_s_ctrl,
+ .g_chip_ident = ov772x_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = ov772x_get_register,
- .set_register = ov772x_set_register,
+ .g_register = ov772x_g_register,
+ .s_register = ov772x_s_register,
#endif
};
+static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
+ .s_stream = ov772x_s_stream,
+ .g_fmt = ov772x_g_fmt,
+ .s_fmt = ov772x_s_fmt,
+ .try_fmt = ov772x_try_fmt,
+ .cropcap = ov772x_cropcap,
+ .g_crop = ov772x_g_crop,
+};
+
+static struct v4l2_subdev_ops ov772x_subdev_ops = {
+ .core = &ov772x_subdev_core_ops,
+ .video = &ov772x_subdev_video_ops,
+};
+
/*
* i2c_driver function
*/
static int ov772x_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+ const struct i2c_device_id *did)
{
struct ov772x_priv *priv;
struct ov772x_camera_info *info;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl;
int ret;
- if (!client->dev.platform_data)
+ if (!icd) {
+ dev_err(&client->dev, "OV772X: missing soc-camera data!\n");
return -EINVAL;
+ }
- info = container_of(client->dev.platform_data,
- struct ov772x_camera_info, link);
+ icl = to_soc_camera_link(icd);
+ if (!icl)
+ return -EINVAL;
+
+ info = container_of(icl, struct ov772x_camera_info, link);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&adapter->dev,
@@ -1084,20 +1159,15 @@ static int ov772x_probe(struct i2c_client *client,
if (!priv)
return -ENOMEM;
- priv->info = info;
- priv->client = client;
- i2c_set_clientdata(client, priv);
+ priv->info = info;
- icd = &priv->icd;
- icd->ops = &ov772x_ops;
- icd->control = &client->dev;
- icd->width_max = MAX_WIDTH;
- icd->height_max = MAX_HEIGHT;
- icd->iface = priv->info->link.bus_id;
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
- ret = soc_camera_device_register(icd);
+ icd->ops = &ov772x_ops;
+ ret = ov772x_video_probe(icd, client);
if (ret) {
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -1107,9 +1177,10 @@ static int ov772x_probe(struct i2c_client *client,
static int ov772x_remove(struct i2c_client *client)
{
- struct ov772x_priv *priv = i2c_get_clientdata(client);
+ struct ov772x_priv *priv = to_ov772x(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&priv->icd);
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 416933ca607d..cc06d5e4adcc 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -65,9 +65,10 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
u32 input;
pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo");
+ sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+ routing_schemes[sid] : NULL;
- if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes[sid]) != NULL) &&
+ if ((sp != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
input = sp->def[hdw->input_val];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 610bd848df24..a334b1a966a2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -540,7 +540,6 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
static struct i2c_adapter pvr2_i2c_adap_template = {
.owner = THIS_MODULE,
.class = 0,
- .id = I2C_HW_B_BT848,
};
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 8d17cf613306..f976df452a34 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1057,7 +1057,8 @@ static int pwc_create_sysfs_files(struct video_device *vdev)
goto err;
if (pdev->features & FEATURE_MOTOR_PANTILT) {
rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt);
- if (rc) goto err_button;
+ if (rc)
+ goto err_button;
}
return 0;
@@ -1072,6 +1073,7 @@ err:
static void pwc_remove_sysfs_files(struct video_device *vdev)
{
struct pwc_device *pdev = video_get_drvdata(vdev);
+
if (pdev->features & FEATURE_MOTOR_PANTILT)
device_remove_file(&vdev->dev, &dev_attr_pan_tilt);
device_remove_file(&vdev->dev, &dev_attr_button);
@@ -1229,13 +1231,11 @@ static void pwc_cleanup(struct pwc_device *pdev)
video_unregister_device(pdev->vdev);
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
- if (pdev->button_dev) {
+ if (pdev->button_dev)
input_unregister_device(pdev->button_dev);
- input_free_device(pdev->button_dev);
- kfree(pdev->button_dev->phys);
- pdev->button_dev = NULL;
- }
#endif
+
+ kfree(pdev);
}
/* Note that all cleanup is done in the reverse order as in _open */
@@ -1281,8 +1281,6 @@ static int pwc_video_close(struct file *file)
PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
} else {
pwc_cleanup(pdev);
- /* Free memory (don't set pdev to 0 just yet) */
- kfree(pdev);
/* search device_hint[] table if we occupy a slot, by any chance */
for (hint = 0; hint < MAX_DEV_HINTS; hint++)
if (device_hint[hint].pdev == pdev)
@@ -1499,13 +1497,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
struct usb_device *udev = interface_to_usbdev(intf);
struct pwc_device *pdev = NULL;
int vendor_id, product_id, type_id;
- int i, hint, rc;
+ int hint, rc;
int features = 0;
int video_nr = -1; /* default: use next available device */
char serial_number[30], *name;
-#ifdef CONFIG_USB_PWC_INPUT_EVDEV
- char *phys = NULL;
-#endif
vendor_id = le16_to_cpu(udev->descriptor.idVendor);
product_id = le16_to_cpu(udev->descriptor.idProduct);
@@ -1757,8 +1752,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vframes = default_fps;
strcpy(pdev->serial, serial_number);
pdev->features = features;
- if (vendor_id == 0x046D && product_id == 0x08B5)
- {
+ if (vendor_id == 0x046D && product_id == 0x08B5) {
/* Logitech QuickCam Orbit
The ranges have been determined experimentally; they may differ from cam to cam.
Also, the exact ranges left-right and up-down are different for my cam
@@ -1780,8 +1774,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev = video_device_alloc();
if (!pdev->vdev) {
PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
- kfree(pdev);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto err_free_mem;
}
memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
pdev->vdev->parent = &intf->dev;
@@ -1806,25 +1800,23 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
}
pdev->vdev->release = video_device_release;
- i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
- if (i < 0) {
- PWC_ERROR("Failed to register as video device (%d).\n", i);
- rc = i;
- goto err;
- }
- else {
- PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
+ rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+ if (rc < 0) {
+ PWC_ERROR("Failed to register as video device (%d).\n", rc);
+ goto err_video_release;
}
+ PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
+
/* occupy slot */
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev;
PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
- usb_set_intfdata (intf, pdev);
+ usb_set_intfdata(intf, pdev);
rc = pwc_create_sysfs_files(pdev->vdev);
if (rc)
- goto err_unreg;
+ goto err_video_unreg;
/* Set the leds off */
pwc_set_leds(pdev, 0, 0);
@@ -1835,16 +1827,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->button_dev = input_allocate_device();
if (!pdev->button_dev) {
PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
- return -ENOMEM;
+ rc = -ENOMEM;
+ pwc_remove_sysfs_files(pdev->vdev);
+ goto err_video_unreg;
}
+ usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
+ strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
+
pdev->button_dev->name = "PWC snapshot button";
- phys = kasprintf(GFP_KERNEL,"usb-%s-%s", pdev->udev->bus->bus_name, pdev->udev->devpath);
- if (!phys) {
- input_free_device(pdev->button_dev);
- return -ENOMEM;
- }
- pdev->button_dev->phys = phys;
+ pdev->button_dev->phys = pdev->button_phys;
usb_to_input_id(pdev->udev, &pdev->button_dev->id);
pdev->button_dev->dev.parent = &pdev->udev->dev;
pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
@@ -1853,25 +1845,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
rc = input_register_device(pdev->button_dev);
if (rc) {
input_free_device(pdev->button_dev);
- kfree(pdev->button_dev->phys);
pdev->button_dev = NULL;
- return rc;
+ pwc_remove_sysfs_files(pdev->vdev);
+ goto err_video_unreg;
}
#endif
return 0;
-err_unreg:
+err_video_unreg:
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = NULL;
video_unregister_device(pdev->vdev);
-err:
- video_device_release(pdev->vdev); /* Drip... drip... drip... */
- kfree(pdev); /* Oops, no memory leaks please */
+ pdev->vdev = NULL; /* So we don't try to release it below */
+err_video_release:
+ video_device_release(pdev->vdev);
+err_free_mem:
+ kfree(pdev);
return rc;
}
-/* The user janked out the cable... */
+/* The user yanked out the cable... */
static void usb_pwc_disconnect(struct usb_interface *intf)
{
struct pwc_device *pdev;
@@ -1902,7 +1896,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
/* Alert waiting processes */
wake_up_interruptible(&pdev->frameq);
/* Wait until device is closed */
- if(pdev->vopen) {
+ if (pdev->vopen) {
mutex_lock(&pdev->modlock);
pdev->unplugged = 1;
mutex_unlock(&pdev->modlock);
@@ -1911,8 +1905,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
/* Device is closed, so we can safely unregister it */
PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
pwc_cleanup(pdev);
- /* Free memory (don't set pdev to 0 just yet) */
- kfree(pdev);
disconnect_out:
/* search device_hint[] table if we occupy a slot, by any chance */
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 2876ce084510..bdb4ced57496 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -1033,7 +1033,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (std->index != 0)
return -EINVAL;
std->id = V4L2_STD_UNKNOWN;
- strncpy(std->name, "webcam", sizeof(std->name));
+ strlcpy(std->name, "webcam", sizeof(std->name));
return 0;
}
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 0b658dee05a4..0902355dfa77 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -135,12 +135,6 @@
#define DEVICE_USE_CODEC3(x) ((x)>=700)
#define DEVICE_USE_CODEC23(x) ((x)>=675)
-
-#ifndef V4L2_PIX_FMT_PWC1
-#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1')
-#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2')
-#endif
-
/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
struct pwc_iso_buf
{
@@ -259,6 +253,7 @@ struct pwc_device
int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
struct input_dev *button_dev; /* webcam snapshot button input */
+ char button_phys[64];
#endif
/*** Misc. data ***/
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 016bb45ba0c3..6952e9602d5d 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -225,6 +225,10 @@ struct pxa_camera_dev {
u32 save_cicr[5];
};
+struct pxa_cam {
+ unsigned long flags;
+};
+
static const char *pxa_cam_driver_description = "PXA_Camera";
static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
@@ -237,9 +241,9 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
{
struct soc_camera_device *icd = vq->priv_data;
- dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+ dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
- *size = roundup(icd->width * icd->height *
+ *size = roundup(icd->user_width * icd->user_height *
((icd->current_fmt->depth + 7) >> 3), 8);
if (0 == *count)
@@ -259,7 +263,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
BUG_ON(in_interrupt());
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
&buf->vb, buf->vb.baddr, buf->vb.bsize);
/* This waits until this buffer is out of danger, i.e., until it is no
@@ -270,7 +274,8 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
if (buf->dmas[i].sg_cpu)
- dma_free_coherent(ici->dev, buf->dmas[i].sg_size,
+ dma_free_coherent(ici->v4l2_dev.dev,
+ buf->dmas[i].sg_size,
buf->dmas[i].sg_cpu,
buf->dmas[i].sg_dma);
buf->dmas[i].sg_cpu = NULL;
@@ -325,19 +330,20 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
struct scatterlist **sg_first, int *sg_first_ofs)
{
struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
struct scatterlist *sg;
int i, offset, sglen;
int dma_len = 0, xfer_len = 0;
if (pxa_dma->sg_cpu)
- dma_free_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
+ dma_free_coherent(dev, pxa_dma->sg_size,
pxa_dma->sg_cpu, pxa_dma->sg_dma);
sglen = calculate_dma_sglen(*sg_first, dma->sglen,
*sg_first_ofs, size);
pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
- pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
+ pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size,
&pxa_dma->sg_dma, GFP_KERNEL);
if (!pxa_dma->sg_cpu)
return -ENOMEM;
@@ -345,7 +351,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
pxa_dma->sglen = sglen;
offset = *sg_first_ofs;
- dev_dbg(pcdev->soc_host.dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
+ dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
*sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
@@ -368,7 +374,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
pxa_dma->sg_cpu[i].ddadr =
pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
- dev_vdbg(pcdev->soc_host.dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
+ dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
sg_dma_address(sg) + offset, xfer_len);
offset = 0;
@@ -418,11 +424,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
struct soc_camera_device *icd = vq->priv_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
int ret;
int size_y, size_u = 0, size_v = 0;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/* Added list head initialization on alloc */
@@ -441,12 +448,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
buf->inwork = 1;
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -480,8 +487,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
&sg, &next_ofs);
if (ret) {
- dev_err(pcdev->soc_host.dev,
- "DMA initialization for Y/RGB failed\n");
+ dev_err(dev, "DMA initialization for Y/RGB failed\n");
goto fail;
}
@@ -490,8 +496,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
size_u, &sg, &next_ofs);
if (ret) {
- dev_err(pcdev->soc_host.dev,
- "DMA initialization for U failed\n");
+ dev_err(dev, "DMA initialization for U failed\n");
goto fail_u;
}
@@ -500,8 +505,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
size_v, &sg, &next_ofs);
if (ret) {
- dev_err(pcdev->soc_host.dev,
- "DMA initialization for V failed\n");
+ dev_err(dev, "DMA initialization for V failed\n");
goto fail_v;
}
@@ -514,10 +518,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
return 0;
fail_v:
- dma_free_coherent(pcdev->soc_host.dev, buf->dmas[1].sg_size,
+ dma_free_coherent(dev, buf->dmas[1].sg_size,
buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
fail_u:
- dma_free_coherent(pcdev->soc_host.dev, buf->dmas[0].sg_size,
+ dma_free_coherent(dev, buf->dmas[0].sg_size,
buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
fail:
free_buffer(vq, buf);
@@ -541,7 +545,8 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
active = pcdev->active;
for (i = 0; i < pcdev->channels; i++) {
- dev_dbg(pcdev->soc_host.dev, "%s (channel=%d) ddadr=%08x\n", __func__,
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (channel=%d) ddadr=%08x\n", __func__,
i, active->dmas[i].sg_dma);
DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
@@ -553,7 +558,8 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
int i;
for (i = 0; i < pcdev->channels; i++) {
- dev_dbg(pcdev->soc_host.dev, "%s (channel=%d)\n", __func__, i);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (channel=%d)\n", __func__, i);
DCSR(pcdev->dma_chans[i]) = 0;
}
}
@@ -589,7 +595,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
{
unsigned long cicr0, cifr;
- dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
/* Reset the FIFOs */
cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
__raw_writel(cifr, pcdev->base + CIFR);
@@ -609,7 +615,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev)
__raw_writel(cicr0, pcdev->base + CICR0);
pcdev->active = NULL;
- dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
}
/* Called under spinlock_irqsave(&pcdev->lock, ...) */
@@ -621,8 +627,8 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
struct pxa_camera_dev *pcdev = ici->priv;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__,
- vb, vb->baddr, vb->bsize, pcdev->active);
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
+ __func__, vb, vb->baddr, vb->bsize, pcdev->active);
list_add_tail(&vb->queue, &pcdev->capture);
@@ -639,22 +645,23 @@ static void pxa_videobuf_release(struct videobuf_queue *vq,
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
#ifdef DEBUG
struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
switch (vb->state) {
case VIDEOBUF_ACTIVE:
- dev_dbg(&icd->dev, "%s (active)\n", __func__);
+ dev_dbg(dev, "%s (active)\n", __func__);
break;
case VIDEOBUF_QUEUED:
- dev_dbg(&icd->dev, "%s (queued)\n", __func__);
+ dev_dbg(dev, "%s (queued)\n", __func__);
break;
case VIDEOBUF_PREPARED:
- dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
+ dev_dbg(dev, "%s (prepared)\n", __func__);
break;
default:
- dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
+ dev_dbg(dev, "%s (unknown)\n", __func__);
break;
}
#endif
@@ -674,7 +681,8 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
do_gettimeofday(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
- dev_dbg(pcdev->soc_host.dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n",
+ __func__, vb);
if (list_empty(&pcdev->capture)) {
pxa_camera_stop_capture(pcdev);
@@ -710,7 +718,8 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
for (i = 0; i < pcdev->channels; i++)
if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
is_dma_stopped = 0;
- dev_dbg(pcdev->soc_host.dev, "%s : top queued buffer=%p, dma_stopped=%d\n",
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s : top queued buffer=%p, dma_stopped=%d\n",
__func__, pcdev->active, is_dma_stopped);
if (pcdev->active && is_dma_stopped)
pxa_camera_start_capture(pcdev);
@@ -719,6 +728,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
enum pxa_camera_active_dma act_dma)
{
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
struct pxa_buffer *buf;
unsigned long flags;
u32 status, camera_status, overrun;
@@ -735,13 +745,13 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
overrun |= CISR_IFO_1 | CISR_IFO_2;
if (status & DCSR_BUSERR) {
- dev_err(pcdev->soc_host.dev, "DMA Bus Error IRQ!\n");
+ dev_err(dev, "DMA Bus Error IRQ!\n");
goto out;
}
if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
- dev_err(pcdev->soc_host.dev, "Unknown DMA IRQ source, "
- "status: 0x%08x\n", status);
+ dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n",
+ status);
goto out;
}
@@ -764,7 +774,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
buf = container_of(vb, struct pxa_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));
- dev_dbg(pcdev->soc_host.dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
+ dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
__func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
@@ -775,7 +785,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
*/
if (camera_status & overrun &&
!list_is_last(pcdev->capture.next, &pcdev->capture)) {
- dev_dbg(pcdev->soc_host.dev, "FIFO overrun! CISR: %x\n",
+ dev_dbg(dev, "FIFO overrun! CISR: %x\n",
camera_status);
pxa_camera_stop_capture(pcdev);
pxa_camera_start_capture(pcdev);
@@ -830,9 +840,11 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
sizeof(struct pxa_buffer), icd);
}
-static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
+static u32 mclk_get_divisor(struct platform_device *pdev,
+ struct pxa_camera_dev *pcdev)
{
unsigned long mclk = pcdev->mclk;
+ struct device *dev = &pdev->dev;
u32 div;
unsigned long lcdclk;
@@ -842,7 +854,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
/* mclk <= ciclk / 4 (27.4.2) */
if (mclk > lcdclk / 4) {
mclk = lcdclk / 4;
- dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk);
+ dev_warn(dev, "Limiting master clock to %lu\n", mclk);
}
/* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
@@ -852,8 +864,8 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
pcdev->mclk = lcdclk / (2 * (div + 1));
- dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, "
- "divisor %u\n", lcdclk, mclk, div);
+ dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n",
+ lcdclk, mclk, div);
return div;
}
@@ -870,14 +882,15 @@ static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
{
struct pxacamera_platform_data *pdata = pcdev->pdata;
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
u32 cicr4 = 0;
- dev_dbg(pcdev->soc_host.dev, "Registered platform device at %p data %p\n",
+ dev_dbg(dev, "Registered platform device at %p data %p\n",
pcdev, pdata);
if (pdata && pdata->init) {
- dev_dbg(pcdev->soc_host.dev, "%s: Init gpios\n", __func__);
- pdata->init(pcdev->soc_host.dev);
+ dev_dbg(dev, "%s: Init gpios\n", __func__);
+ pdata->init(dev);
}
/* disable all interrupts */
@@ -919,7 +932,8 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
struct videobuf_buffer *vb;
status = __raw_readl(pcdev->base + CISR);
- dev_dbg(pcdev->soc_host.dev, "Camera interrupt status 0x%lx\n", status);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "Camera interrupt status 0x%lx\n", status);
if (!status)
return IRQ_NONE;
@@ -951,24 +965,18 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
- int ret;
- if (pcdev->icd) {
- ret = -EBUSY;
- goto ebusy;
- }
-
- dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
- icd->devnum);
+ if (pcdev->icd)
+ return -EBUSY;
pxa_camera_activate(pcdev);
- ret = icd->ops->init(icd);
- if (!ret)
- pcdev->icd = icd;
+ pcdev->icd = icd;
-ebusy:
- return ret;
+ dev_info(icd->dev.parent, "PXA Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
}
/* Called with .video_lock held */
@@ -979,7 +987,7 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
BUG_ON(icd != pcdev->icd);
- dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n",
+ dev_info(icd->dev.parent, "PXA Camera driver detached from camera %d\n",
icd->devnum);
/* disable capture, disable interrupts */
@@ -990,8 +998,6 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
DCSR(pcdev->dma_chans[1]) = 0;
DCSR(pcdev->dma_chans[2]) = 0;
- icd->ops->release(icd);
-
pxa_camera_deactivate(pcdev);
pcdev->icd = NULL;
@@ -1039,57 +1045,17 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
return 0;
}
-static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
+ unsigned long flags, __u32 pixfmt)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
- unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
+ unsigned long dw, bpp;
u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0;
- int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
-
- if (ret < 0)
- return ret;
-
- camera_flags = icd->ops->query_bus_param(icd);
-
- common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
- if (!common_flags)
- return -EINVAL;
-
- pcdev->channels = 1;
-
- /* Make choises, based on platform preferences */
- if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
- (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_HSP)
- common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
- }
-
- if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
- (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_VSP)
- common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
- }
-
- if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
- (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
- if (pcdev->platform_flags & PXA_CAMERA_PCP)
- common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
- else
- common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
- }
-
- ret = icd->ops->set_bus_param(icd, common_flags);
- if (ret < 0)
- return ret;
/* Datawidth is now guaranteed to be equal to one of the three values.
* We fix bit-per-pixel equal to data-width... */
- switch (common_flags & SOCAM_DATAWIDTH_MASK) {
+ switch (flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_10:
dw = 4;
bpp = 0x40;
@@ -1110,18 +1076,18 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
cicr4 |= CICR4_PCLK_EN;
if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
cicr4 |= CICR4_MCLK_EN;
- if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+ if (flags & SOCAM_PCLK_SAMPLE_FALLING)
cicr4 |= CICR4_PCP;
- if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+ if (flags & SOCAM_HSYNC_ACTIVE_LOW)
cicr4 |= CICR4_HSP;
- if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+ if (flags & SOCAM_VSYNC_ACTIVE_LOW)
cicr4 |= CICR4_VSP;
cicr0 = __raw_readl(pcdev->base + CICR0);
if (cicr0 & CICR0_ENB)
__raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
- cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+ cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw;
switch (pixfmt) {
case V4L2_PIX_FMT_YUV422P:
@@ -1150,7 +1116,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
}
cicr2 = 0;
- cicr3 = CICR3_LPF_VAL(icd->height - 1) |
+ cicr3 = CICR3_LPF_VAL(icd->user_height - 1) |
CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
cicr4 |= pcdev->mclk_divisor;
@@ -1164,6 +1130,59 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP));
cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK;
__raw_writel(cicr0, pcdev->base + CICR0);
+}
+
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ unsigned long bus_flags, camera_flags, common_flags;
+ int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+ struct pxa_cam *cam = icd->host_priv;
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ if (!common_flags)
+ return -EINVAL;
+
+ pcdev->channels = 1;
+
+ /* Make choises, based on platform preferences */
+ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & PXA_CAMERA_HSP)
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & PXA_CAMERA_VSP)
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+ else
+ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+ }
+
+ cam->flags = common_flags;
+
+ ret = icd->ops->set_bus_param(icd, common_flags);
+ if (ret < 0)
+ return ret;
+
+ pxa_camera_setup_cicr(icd, common_flags, pixfmt);
return 0;
}
@@ -1227,8 +1246,9 @@ static int required_buswidth(const struct soc_camera_data_format *fmt)
static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
struct soc_camera_format_xlate *xlate)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct device *dev = icd->dev.parent;
int formats = 0, buswidth, ret;
+ struct pxa_cam *cam;
buswidth = required_buswidth(icd->formats + idx);
@@ -1239,6 +1259,16 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
if (ret < 0)
return 0;
+ if (!icd->host_priv) {
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam)
+ return -ENOMEM;
+
+ icd->host_priv = cam;
+ } else {
+ cam = icd->host_priv;
+ }
+
switch (icd->formats[idx].fourcc) {
case V4L2_PIX_FMT_UYVY:
formats++;
@@ -1247,7 +1277,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(dev, "Providing format %s using %s\n",
pxa_camera_formats[0].name,
icd->formats[idx].name);
}
@@ -1262,7 +1292,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s packed\n",
+ dev_dbg(dev, "Providing format %s packed\n",
icd->formats[idx].name);
}
break;
@@ -1274,7 +1304,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = icd->formats[idx].depth;
xlate++;
- dev_dbg(ici->dev,
+ dev_dbg(dev,
"Providing format %s in pass-through mode\n",
icd->formats[idx].name);
}
@@ -1283,31 +1313,80 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
return formats;
}
+static void pxa_camera_put_formats(struct soc_camera_device *icd)
+{
+ kfree(icd->host_priv);
+ icd->host_priv = NULL;
+}
+
+static int pxa_camera_check_frame(struct v4l2_pix_format *pix)
+{
+ /* limit to pxa hardware capabilities */
+ return pix->height < 32 || pix->height > 2048 || pix->width < 48 ||
+ pix->width > 2048 || (pix->width & 0x01);
+}
+
static int pxa_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
+ struct v4l2_rect *rect = &a->c;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
+ struct device *dev = icd->dev.parent;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_sense sense = {
.master_clock = pcdev->mclk,
.pixel_clock_max = pcdev->ciclk / 4,
};
+ struct v4l2_format f;
+ struct v4l2_pix_format *pix = &f.fmt.pix, pix_tmp;
+ struct pxa_cam *cam = icd->host_priv;
int ret;
/* If PCLK is used to latch data from the sensor, check sense */
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
icd->sense = &sense;
- ret = icd->ops->set_crop(icd, rect);
+ ret = v4l2_subdev_call(sd, video, s_crop, a);
icd->sense = NULL;
if (ret < 0) {
- dev_warn(ici->dev, "Failed to crop to %ux%u@%u:%u\n",
+ dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n",
rect->width, rect->height, rect->left, rect->top);
- } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+ return ret;
+ }
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ pix_tmp = *pix;
+ if (pxa_camera_check_frame(pix)) {
+ /*
+ * Camera cropping produced a frame beyond our capabilities.
+ * FIXME: just extract a subframe, that we can process.
+ */
+ v4l_bound_align_image(&pix->width, 48, 2048, 1,
+ &pix->height, 32, 2048, 0,
+ icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ?
+ 4 : 0);
+ ret = v4l2_subdev_call(sd, video, s_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ if (pxa_camera_check_frame(pix)) {
+ dev_warn(icd->dev.parent,
+ "Inconsistent state. Use S_FMT to repair\n");
+ return -EINVAL;
+ }
+ }
+
+ if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
if (sense.pixel_clock > sense.pixel_clock_max) {
- dev_err(ici->dev,
+ dev_err(dev,
"pixel clock %lu set by the camera too high!",
sense.pixel_clock);
return -EIO;
@@ -1315,6 +1394,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
recalculate_fifo_timeout(pcdev, sense.pixel_clock);
}
+ icd->user_width = pix->width;
+ icd->user_height = pix->height;
+
+ pxa_camera_setup_cicr(icd, cam->flags, icd->current_fmt->fourcc);
+
return ret;
}
@@ -1323,6 +1407,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
+ struct device *dev = icd->dev.parent;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_data_format *cam_fmt = NULL;
const struct soc_camera_format_xlate *xlate = NULL;
struct soc_camera_sense sense = {
@@ -1335,7 +1421,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
+ dev_warn(dev, "Format %x not found\n", pix->pixelformat);
return -EINVAL;
}
@@ -1346,16 +1432,21 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
icd->sense = &sense;
cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
- ret = icd->ops->set_fmt(icd, &cam_f);
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
icd->sense = NULL;
if (ret < 0) {
- dev_warn(ici->dev, "Failed to configure for format %x\n",
+ dev_warn(dev, "Failed to configure for format %x\n",
pix->pixelformat);
+ } else if (pxa_camera_check_frame(pix)) {
+ dev_warn(dev,
+ "Camera driver produced an unsupported frame %dx%d\n",
+ pix->width, pix->height);
+ ret = -EINVAL;
} else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
if (sense.pixel_clock > sense.pixel_clock_max) {
- dev_err(ici->dev,
+ dev_err(dev,
"pixel clock %lu set by the camera too high!",
sense.pixel_clock);
return -EIO;
@@ -1375,6 +1466,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
__u32 pixfmt = pix->pixelformat;
@@ -1383,7 +1475,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
@@ -1395,7 +1487,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
*/
v4l_bound_align_image(&pix->width, 48, 2048, 1,
&pix->height, 32, 2048, 0,
- xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+ pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
pix->bytesperline = pix->width *
DIV_ROUND_UP(xlate->host_fmt->depth, 8);
@@ -1404,15 +1496,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
/* camera has to see its format, but the user the original one */
pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- ret = icd->ops->try_fmt(icd, f);
- pix->pixelformat = xlate->host_fmt->fourcc;
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
+ pix->pixelformat = pixfmt;
field = pix->field;
if (field == V4L2_FIELD_ANY) {
pix->field = V4L2_FIELD_NONE;
} else if (field != V4L2_FIELD_NONE) {
- dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+ dev_err(icd->dev.parent, "Field type %d unsupported.\n", field);
return -EINVAL;
}
@@ -1518,6 +1610,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.resume = pxa_camera_resume,
.set_crop = pxa_camera_set_crop,
.get_formats = pxa_camera_get_formats,
+ .put_formats = pxa_camera_put_formats,
.set_fmt = pxa_camera_set_fmt,
.try_fmt = pxa_camera_try_fmt,
.init_videobuf = pxa_camera_init_videobuf,
@@ -1575,8 +1668,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
pcdev->mclk = 20000000;
}
- pcdev->soc_host.dev = &pdev->dev;
- pcdev->mclk_divisor = mclk_get_divisor(pcdev);
+ pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev);
INIT_LIST_HEAD(&pcdev->capture);
spin_lock_init(&pcdev->lock);
@@ -1641,6 +1733,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME;
pcdev->soc_host.ops = &pxa_soc_camera_host_ops;
pcdev->soc_host.priv = pcdev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
err = soc_camera_host_register(&pcdev->soc_host);
@@ -1722,3 +1815,4 @@ module_exit(pxa_camera_exit);
MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index c25e81af5ce0..c3e96f070973 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -40,7 +40,7 @@
/* insmod options */
static unsigned int debug;
static unsigned int xtal;
-static unsigned int rbds;
+static unsigned int mmbs;
static unsigned int plvl;
static unsigned int bufblocks = 100;
@@ -48,8 +48,8 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
module_param(xtal, int, 0);
MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0");
-module_param(rbds, int, 0);
-MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0");
+module_param(mmbs, int, 0);
+MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on");
module_param(plvl, int, 0);
MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0");
module_param(bufblocks, int, 0);
@@ -78,6 +78,7 @@ struct saa6588 {
unsigned char last_blocknum;
wait_queue_head_t read_queue;
int data_available_for_read;
+ u8 sync;
};
static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
@@ -261,13 +262,16 @@ static void saa6588_i2c_poll(struct saa6588 *s)
unsigned char tmp;
/* Although we only need 3 bytes, we have to read at least 6.
- SAA6588 returns garbage otherwise */
+ SAA6588 returns garbage otherwise. */
if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
if (debug > 1)
dprintk(PREFIX "read error!\n");
return;
}
+ s->sync = tmpbuf[0] & 0x10;
+ if (!s->sync)
+ return;
blocknum = tmpbuf[0] >> 5;
if (blocknum == s->last_blocknum) {
if (debug > 3)
@@ -286,9 +290,8 @@ static void saa6588_i2c_poll(struct saa6588 *s)
occurred during reception of this block.
Bit 6: Corrected bit. Indicates that an error was
corrected for this data block.
- Bits 5-3: Received Offset. Indicates the offset received
- by the sync system.
- Bits 2-0: Offset Name. Indicates the offset applied to this data.
+ Bits 5-3: Same as bits 0-2.
+ Bits 2-0: Block number.
SAA6588 byte order is Status-MSB-LSB, so we have to swap the
first and the last of the 3 bytes block.
@@ -298,12 +301,21 @@ static void saa6588_i2c_poll(struct saa6588 *s)
tmpbuf[2] = tmpbuf[0];
tmpbuf[0] = tmp;
+ /* Map 'Invalid block E' to 'Invalid Block' */
+ if (blocknum == 6)
+ blocknum = V4L2_RDS_BLOCK_INVALID;
+ /* And if are not in mmbs mode, then 'Block E' is also mapped
+ to 'Invalid Block'. As far as I can tell MMBS is discontinued,
+ and if there is ever a need to support E blocks, then please
+ contact the linux-media mailinglist. */
+ else if (!mmbs && blocknum == 5)
+ blocknum = V4L2_RDS_BLOCK_INVALID;
tmp = blocknum;
tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */
if ((tmpbuf[2] & 0x03) == 0x03)
- tmp |= 0x80; /* uncorrectable error */
+ tmp |= V4L2_RDS_BLOCK_ERROR; /* uncorrectable error */
else if ((tmpbuf[2] & 0x03) != 0x00)
- tmp |= 0x40; /* corrected error */
+ tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */
tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */
spin_lock_irqsave(&s->lock, flags);
@@ -321,14 +333,14 @@ static void saa6588_work(struct work_struct *work)
schedule_delayed_work(&s->work, msecs_to_jiffies(20));
}
-static int saa6588_configure(struct saa6588 *s)
+static void saa6588_configure(struct saa6588 *s)
{
struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
unsigned char buf[3];
int rc;
buf[0] = cSyncRestart;
- if (rbds)
+ if (mmbs)
buf[0] |= cProcessingModeRBDS;
buf[1] = cFlywheelDefault;
@@ -374,8 +386,6 @@ static int saa6588_configure(struct saa6588 *s)
rc = i2c_master_send(client, buf, 3);
if (rc != 3)
printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
-
- return 0;
}
/* ---------------------------------------------------------------------- */
@@ -416,6 +426,24 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return 0;
}
+static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa6588 *s = to_saa6588(sd);
+
+ vt->capability |= V4L2_TUNER_CAP_RDS;
+ if (s->sync)
+ vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+ return 0;
+}
+
+static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa6588 *s = to_saa6588(sd);
+
+ saa6588_configure(s);
+ return 0;
+}
+
static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -430,8 +458,14 @@ static const struct v4l2_subdev_core_ops saa6588_core_ops = {
.ioctl = saa6588_ioctl,
};
+static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
+ .g_tuner = saa6588_g_tuner,
+ .s_tuner = saa6588_s_tuner,
+};
+
static const struct v4l2_subdev_ops saa6588_ops = {
.core = &saa6588_core_ops,
+ .tuner = &saa6588_tuner_ops,
};
/* ---------------------------------------------------------------------- */
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 5bcce092e804..22bfd62c9551 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -47,6 +47,7 @@ config VIDEO_SAA7134_DVB
select DVB_TDA10048 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+ select DVB_ZL10039 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 63c4b8f1f541..1eabff6b2456 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -468,7 +468,7 @@ static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
(!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
return -ERANGE;
- new = old;
+ params->au_encoding = new;
break;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
old = params->au_l2_bitrate;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 8b0b64a89874..d48c450ed77c 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -40,6 +40,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
*/
/* defaults */
+#define MIXER_ADDR_UNSELECTED -1
#define MIXER_ADDR_TVTUNER 0
#define MIXER_ADDR_LINE1 1
#define MIXER_ADDR_LINE2 2
@@ -68,7 +69,9 @@ typedef struct snd_card_saa7134 {
struct snd_card *card;
spinlock_t mixer_lock;
int mixer_volume[MIXER_ADDR_LAST+1][2];
- int capture_source[MIXER_ADDR_LAST+1][2];
+ int capture_source_addr;
+ int capture_source[2];
+ struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1];
struct pci_dev *pci;
struct saa7134_dev *dev;
@@ -314,6 +317,115 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
return 0;
}
+/*
+ * Setting the capture source and updating the ALSA controls
+ */
+static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol,
+ int left, int right, bool force_notify)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int change = 0, addr = kcontrol->private_value;
+ int active, old_addr;
+ u32 anabar, xbarin;
+ int analog_io, rate;
+ struct saa7134_dev *dev;
+
+ dev = chip->dev;
+
+ spin_lock_irq(&chip->mixer_lock);
+
+ active = left != 0 || right != 0;
+ old_addr = chip->capture_source_addr;
+
+ /* The active capture source cannot be deactivated */
+ if (active) {
+ change = old_addr != addr ||
+ chip->capture_source[0] != left ||
+ chip->capture_source[1] != right;
+
+ chip->capture_source[0] = left;
+ chip->capture_source[1] = right;
+ chip->capture_source_addr = addr;
+ dev->dmasound.input = addr;
+ }
+ spin_unlock_irq(&chip->mixer_lock);
+
+ if (change) {
+ switch (dev->pci->device) {
+
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+ 0xc0, 0xc0);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+ 0x03, 0x00);
+ break;
+ case MIXER_ADDR_LINE1:
+ case MIXER_ADDR_LINE2:
+ analog_io = (MIXER_ADDR_LINE1 == addr) ?
+ 0x00 : 0x08;
+ rate = (32000 == dev->dmasound.rate) ?
+ 0x01 : 0x03;
+ saa_andorb(SAA7134_ANALOG_IO_SELECT,
+ 0x08, analog_io);
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+ 0xc0, 0x80);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+ 0x03, rate);
+ break;
+ }
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ xbarin = 0x03; /* adc */
+ anabar = 0;
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ xbarin = 0; /* Demodulator */
+ anabar = 2; /* DACs */
+ break;
+ case MIXER_ADDR_LINE1:
+ anabar = 0; /* aux1, aux1 */
+ break;
+ case MIXER_ADDR_LINE2:
+ anabar = 9; /* aux2, aux2 */
+ break;
+ }
+
+ /* output xbar always main channel */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1,
+ 0xbbbb10);
+
+ if (left || right) {
+ /* We've got data, turn the input on */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+ xbarin);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+ } else {
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+ 0);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+ }
+ break;
+ }
+ }
+
+ if (change) {
+ if (force_notify)
+ snd_ctl_notify(chip->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->capture_ctl[addr]->id);
+
+ if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr)
+ snd_ctl_notify(chip->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->capture_ctl[old_addr]->id);
+ }
+
+ return change;
+}
/*
* ALSA PCM preparation
@@ -401,6 +513,10 @@ static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream
dev->dmasound.rate = runtime->rate;
+ /* Setup and update the card/ALSA controls */
+ snd_saa7134_capsrc_set(saa7134->capture_ctl[dev->dmasound.input], 1, 1,
+ true);
+
return 0;
}
@@ -435,6 +551,16 @@ snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream)
/*
* ALSA hardware capabilities definition
+ *
+ * Report only 32kHz for ALSA:
+ *
+ * - SAA7133/35 uses DDEP (DemDec Easy Programming mode), which works in 32kHz
+ * only
+ * - SAA7134 for TV mode uses DemDec mode (32kHz)
+ * - Radio works in 32kHz only
+ * - When recording 48kHz from Line1/Line2, switching of capture source to TV
+ * means
+ * switching to 32kHz without any frequency translation
*/
static struct snd_pcm_hardware snd_card_saa7134_capture =
@@ -448,9 +574,9 @@ static struct snd_pcm_hardware snd_card_saa7134_capture =
SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_U16_LE | \
SNDRV_PCM_FMTBIT_U16_BE,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .rates = SNDRV_PCM_RATE_32000,
.rate_min = 32000,
- .rate_max = 48000,
+ .rate_max = 32000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (256*1024),
@@ -836,8 +962,13 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
int addr = kcontrol->private_value;
spin_lock_irq(&chip->mixer_lock);
- ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
- ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+ if (chip->capture_source_addr == addr) {
+ ucontrol->value.integer.value[0] = chip->capture_source[0];
+ ucontrol->value.integer.value[1] = chip->capture_source[1];
+ } else {
+ ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.integer.value[1] = 0;
+ }
spin_unlock_irq(&chip->mixer_lock);
return 0;
@@ -846,87 +977,22 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
struct snd_ctl_elem_value * ucontrol)
{
- snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
- int change, addr = kcontrol->private_value;
int left, right;
- u32 anabar, xbarin;
- int analog_io, rate;
- struct saa7134_dev *dev;
-
- dev = chip->dev;
-
left = ucontrol->value.integer.value[0] & 1;
right = ucontrol->value.integer.value[1] & 1;
- spin_lock_irq(&chip->mixer_lock);
-
- change = chip->capture_source[addr][0] != left ||
- chip->capture_source[addr][1] != right;
- chip->capture_source[addr][0] = left;
- chip->capture_source[addr][1] = right;
- dev->dmasound.input=addr;
- spin_unlock_irq(&chip->mixer_lock);
-
-
- if (change) {
- switch (dev->pci->device) {
-
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- switch (addr) {
- case MIXER_ADDR_TVTUNER:
- saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
- saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
- break;
- case MIXER_ADDR_LINE1:
- case MIXER_ADDR_LINE2:
- analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08;
- rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
- saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io);
- saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
- saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
- break;
- }
-
- break;
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- xbarin = 0x03; // adc
- anabar = 0;
- switch (addr) {
- case MIXER_ADDR_TVTUNER:
- xbarin = 0; // Demodulator
- anabar = 2; // DACs
- break;
- case MIXER_ADDR_LINE1:
- anabar = 0; // aux1, aux1
- break;
- case MIXER_ADDR_LINE2:
- anabar = 9; // aux2, aux2
- break;
- }
-
- /* output xbar always main channel */
- saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
- if (left || right) { // We've got data, turn the input on
- saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin);
- saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
- } else {
- saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0);
- saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
- }
- break;
- }
- }
-
- return change;
+ return snd_saa7134_capsrc_set(kcontrol, left, right, false);
}
-static struct snd_kcontrol_new snd_saa7134_controls[] = {
+static struct snd_kcontrol_new snd_saa7134_volume_controls[] = {
SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
-SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
-SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+};
+
+static struct snd_kcontrol_new snd_saa7134_capture_controls[] = {
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
};
@@ -941,17 +1007,33 @@ SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
{
struct snd_card *card = chip->card;
+ struct snd_kcontrol *kcontrol;
unsigned int idx;
- int err;
+ int err, addr;
if (snd_BUG_ON(!chip))
return -EINVAL;
strcpy(card->mixername, "SAA7134 Mixer");
- for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
- if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0)
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
+ kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx],
+ chip);
+ err = snd_ctl_add(card, kcontrol);
+ if (err < 0)
return err;
}
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) {
+ kcontrol = snd_ctl_new1(&snd_saa7134_capture_controls[idx],
+ chip);
+ addr = snd_saa7134_capture_controls[idx].private_value;
+ chip->capture_ctl[addr] = kcontrol;
+ err = snd_ctl_add(card, kcontrol);
+ if (err < 0)
+ return err;
+ }
+
+ chip->capture_source_addr = MIXER_ADDR_UNSELECTED;
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 6eebe3ef97d3..1b29487fd254 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -32,6 +32,7 @@
#include <media/tveeprom.h>
#include "tea5767.h"
#include "tda18271.h"
+#include "xc5000.h"
/* commly used strings */
static char name_mute[] = "mute";
@@ -265,6 +266,56 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x10000,
},
},
+ [SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM] = {
+ /* RoverMedia TV Link Pro FM (LR138 REV:I) */
+ /* Eugene Yudin <Eugene.Yudin@gmail.com> */
+ .name = "RoverMedia TV Link Pro FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MFPE05 2 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0xe000,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ .tv = 1,
+ }, {
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }, {
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
[SAA7134_BOARD_EMPRESS] = {
/* "Gert Vervoort" <gert.vervoort@philips.com> */
.name = "EMPRESS",
@@ -1364,6 +1415,42 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
},
},
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_505] = {
+ /* Vasiliy Temnikov <vaka@newmail.ru> */
+ .name = "AverMedia AverTV Studio 505",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
[SAA7134_BOARD_UPMOST_PURPLE_TV] = {
.name = "UPMOST PURPLE TV",
.audio_clock = 0x00187de7,
@@ -1633,7 +1720,7 @@ struct saa7134_board saa7134_boards[] = {
}},
.radio = {
.name = name_radio,
- .amux = LINE1,
+ .amux = TV,
.gpio = 0x00300001,
},
.mute = {
@@ -3663,8 +3750,8 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
.gpio = 0x0200000,
},
- },
- [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
+ },
+ [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
.name = "ASUSTeK P7131 Analog",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_TDA8290,
@@ -4081,6 +4168,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
@@ -4145,6 +4233,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
@@ -4175,6 +4264,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
@@ -4350,6 +4440,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4378,6 +4469,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4406,6 +4498,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4434,6 +4527,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4540,6 +4634,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
@@ -4861,7 +4956,7 @@ struct saa7134_board saa7134_boards[] = {
/* Igor Kuznetsov <igk@igk.ru> */
.name = "Beholder BeholdTV H6",
.audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .tuner_type = TUNER_PHILIPS_FMD1216MEX_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -5116,6 +5211,53 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x00,
},
},
+ [SAA7134_BOARD_VIDEOMATE_S350] = {
+ /* Jan D. Louw <jd.louw@mweb.co.za */
+ .name = "Compro VideoMate S350/S300",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8, /* Not tested */
+ .amux = LINE1
+ } },
+ },
+ [SAA7134_BOARD_BEHOLD_X7] = {
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV X7",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC5000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 2,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 9,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ },
+ },
+
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5374,6 +5516,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa115,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
.subdevice = 0x2108,
.driver_data = SAA7134_BOARD_AVERMEDIA_305,
},{
@@ -6223,7 +6371,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x1461, /* Avermedia Technologies Inc */
.subdevice = 0xf31d,
.driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS,
-
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_S350,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7595,
+ .driver_data = SAA7134_BOARD_BEHOLD_X7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x19d1, /* RoverMedia */
+ .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */
+ .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM,
}, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
@@ -6310,6 +6475,32 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
return -EINVAL;
}
+static int saa7134_xc5000_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ switch (dev->board) {
+ case SAA7134_BOARD_BEHOLD_X7:
+ if (command == XC5000_TUNER_RESET) {
+ /* Down and UP pheripherial RESET pin for reset all chips */
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+ msleep(10);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+ msleep(10);
+ }
+ break;
+ default:
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+ saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
+ saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
+ saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
+ saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
+ saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
+ 0x0001e000, 0x0001e000);
+ break;
+ }
+ return 0;
+}
static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
int command, int arg)
@@ -6406,6 +6597,8 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg)
return saa7134_tda8290_callback(dev, command, arg);
case TUNER_XC2028:
return saa7134_xc2028_callback(dev, command, arg);
+ case TUNER_XC5000:
+ return saa7134_xc5000_callback(dev, command, arg);
}
} else {
printk(KERN_ERR "saa7134: Error - device struct undefined.\n");
@@ -6476,6 +6669,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
case SAA7134_BOARD_KWORLD_XPERT:
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
case SAA7134_BOARD_AVERMEDIA_305:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_307:
@@ -6500,7 +6694,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_FLYDVBT_LR301:
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+ case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_PROTEUS_2309:
case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -6525,6 +6719,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_REAL_ANGEL_220:
case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+ case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -6653,6 +6848,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_M63:
case SAA7134_BOARD_BEHOLD_M6_EXTRA:
case SAA7134_BOARD_BEHOLD_H6:
+ case SAA7134_BOARD_BEHOLD_X7:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -6673,6 +6869,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00008000, 0x00008000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ break;
}
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 94a023a14bbc..cb78c956d810 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1012,8 +1012,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
sd = v4l2_i2c_new_probed_subdev_addr(&dev->v4l2_dev,
&dev->i2c_adap, "saa6588", "saa6588",
saa7134_boards[dev->board].rds_addr);
- if (sd)
+ if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
+ dev->has_rds = 1;
+ }
}
request_submodules(dev);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 98f3efd1e944..ebde21dba7e3 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -56,6 +56,7 @@
#include "zl10353.h"
#include "zl10036.h"
+#include "zl10039.h"
#include "mt312.h"
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -968,6 +969,10 @@ static struct zl10036_config avertv_a700_tuner = {
.tuner_address = 0x60,
};
+static struct mt312_config zl10313_compro_s350_config = {
+ .demod_address = 0x0e,
+};
+
static struct lgdt3305_config hcw_lgdt3305_config = {
.i2c_addr = 0x0e,
.mpeg_mode = LGDT3305_MPEG_SERIAL,
@@ -1457,7 +1462,7 @@ static int dvb_init(struct saa7134_dev *dev)
if (fe0->dvb.frontend) {
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0x61,
- TUNER_PHILIPS_FMD1216ME_MK3);
+ TUNER_PHILIPS_FMD1216MEX_MK3);
}
break;
case SAA7134_BOARD_AVERMEDIA_A700_PRO:
@@ -1473,6 +1478,16 @@ static int dvb_init(struct saa7134_dev *dev)
}
}
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &zl10313_compro_s350_config, &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap) == NULL)
+ wprintk("%s: No zl10039 found!\n",
+ __func__);
+
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 6e219c2db841..65fb7b17b678 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -415,6 +415,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_FLYVIDEO3000:
case SAA7134_BOARD_FLYTVPLATINUM_FM:
case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
+ case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
ir_codes = ir_codes_flyvideo;
mask_keycode = 0xEC00000;
mask_keydown = 0x0040000;
@@ -445,6 +446,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_305:
case SAA7134_BOARD_AVERMEDIA_307:
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
@@ -564,7 +566,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+ case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
ir_codes = ir_codes_asus_pc39;
mask_keydown = 0x0040000;
rc5_gpio = 1;
@@ -605,6 +607,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0x7f;
polling = 40; /* ms */
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ ir_codes = ir_codes_videomate_s350;
+ mask_keycode = 0x003f00;
+ mask_keydown = 0x040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -716,9 +723,11 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
if (pinnacle_remote == 0) {
init_data.get_key = get_key_pinnacle_color;
init_data.ir_codes = ir_codes_pinnacle_color;
+ info.addr = 0x47;
} else {
init_data.get_key = get_key_pinnacle_grey;
init_data.ir_codes = ir_codes_pinnacle_grey;
+ info.addr = 0x47;
}
break;
case SAA7134_BOARD_UPMOST_PURPLE_TV:
@@ -757,6 +766,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_M63:
case SAA7134_BOARD_BEHOLD_M6_EXTRA:
case SAA7134_BOARD_BEHOLD_H6:
+ case SAA7134_BOARD_BEHOLD_X7:
init_data.name = "BeholdTV";
init_data.get_key = get_key_beholdm6xx;
init_data.ir_codes = ir_codes_behold;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index ba87128542e0..da26f476a302 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1444,7 +1444,6 @@ video_poll(struct file *file, struct poll_table_struct *wait)
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- mutex_unlock(&fh->cap.vb_lock);
buf = fh->cap.read_buf;
}
@@ -1790,7 +1789,7 @@ static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
if (0 != err)
return err;
- if (i < 0 || i >= SAA7134_INPUT_MAX)
+ if (i >= SAA7134_INPUT_MAX)
return -EINVAL;
if (NULL == card_in(dev, i).name)
return -EINVAL;
@@ -1819,6 +1818,8 @@ static int saa7134_querycap(struct file *file, void *priv,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_TUNER;
+ if (dev->has_rds)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (saa7134_no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index fb564f14887c..ac74903a5bd4 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -292,6 +292,10 @@ struct saa7134_format {
#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166
#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167
#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168
+#define SAA7134_BOARD_VIDEOMATE_S350 169
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170
+#define SAA7134_BOARD_BEHOLD_X7 171
+#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -539,6 +543,7 @@ struct saa7134_dev {
struct i2c_adapter i2c_adap;
struct i2c_client i2c_client;
unsigned char eedata[256];
+ int has_rds;
/* video overlay */
struct v4l2_framebuffer ovbuf;
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 61c47b824083..c56bf16de593 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -74,6 +74,13 @@
#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
+#undef DEBUG_GEOMETRY
+#ifdef DEBUG_GEOMETRY
+#define dev_geo dev_info
+#else
+#define dev_geo dev_dbg
+#endif
+
/* per video frame buffer */
struct sh_mobile_ceu_buffer {
struct videobuf_buffer vb; /* v4l buffer must be first */
@@ -92,10 +99,21 @@ struct sh_mobile_ceu_dev {
spinlock_t lock;
struct list_head capture;
struct videobuf_buffer *active;
- int is_interlaced;
struct sh_mobile_ceu_info *pdata;
+ u32 cflcr;
+
+ unsigned int is_interlaced:1;
+ unsigned int image_mode:1;
+ unsigned int is_16bit:1;
+};
+
+struct sh_mobile_ceu_cam {
+ struct v4l2_rect ceu_rect;
+ unsigned int cam_width;
+ unsigned int cam_height;
+ const struct soc_camera_data_format *extra_fmt;
const struct soc_camera_data_format *camera_fmt;
};
@@ -146,7 +164,8 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
struct sh_mobile_ceu_dev *pcdev = ici->priv;
int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
- *size = PAGE_ALIGN(icd->width * icd->height * bytes_per_pixel);
+ *size = PAGE_ALIGN(icd->user_width * icd->user_height *
+ bytes_per_pixel);
if (0 == *count)
*count = 2;
@@ -156,7 +175,7 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
(*count)--;
}
- dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+ dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
return 0;
}
@@ -165,8 +184,9 @@ static void free_buffer(struct videobuf_queue *vq,
struct sh_mobile_ceu_buffer *buf)
{
struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
&buf->vb, buf->vb.baddr, buf->vb.bsize);
if (in_interrupt())
@@ -174,7 +194,7 @@ static void free_buffer(struct videobuf_queue *vq,
videobuf_waiton(&buf->vb, 0, 0);
videobuf_dma_contig_free(vq, &buf->vb);
- dev_dbg(&icd->dev, "%s freed\n", __func__);
+ dev_dbg(dev, "%s freed\n", __func__);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -205,7 +225,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
phys_addr_top = videobuf_to_dma_contig(pcdev->active);
ceu_write(pcdev, CDAYR, phys_addr_top);
if (pcdev->is_interlaced) {
- phys_addr_bottom = phys_addr_top + icd->width;
+ phys_addr_bottom = phys_addr_top + icd->user_width;
ceu_write(pcdev, CDBYR, phys_addr_bottom);
}
@@ -214,10 +234,12 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
- phys_addr_top += icd->width * icd->height;
+ phys_addr_top += icd->user_width *
+ icd->user_height;
ceu_write(pcdev, CDACR, phys_addr_top);
if (pcdev->is_interlaced) {
- phys_addr_bottom = phys_addr_top + icd->width;
+ phys_addr_bottom = phys_addr_top +
+ icd->user_width;
ceu_write(pcdev, CDBCR, phys_addr_bottom);
}
}
@@ -236,7 +258,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
buf = container_of(vb, struct sh_mobile_ceu_buffer, vb);
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
/* Added list head initialization on alloc */
@@ -251,12 +273,12 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
BUG_ON(NULL == icd->current_fmt);
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -289,7 +311,7 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
vb->state = VIDEOBUF_QUEUED;
@@ -304,6 +326,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (pcdev->active == vb) {
+ /* disable capture (release DMA buffer), reset */
+ ceu_write(pcdev, CAPSR, 1 << 16);
+ pcdev->active = NULL;
+ }
+
+ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+ !list_empty(&vb->queue)) {
+ vb->state = VIDEOBUF_ERROR;
+ list_del_init(&vb->queue);
+ }
+
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));
}
@@ -323,6 +366,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
spin_lock_irqsave(&pcdev->lock, flags);
vb = pcdev->active;
+ if (!vb)
+ /* Stale interrupt from a released buffer */
+ goto out;
+
list_del_init(&vb->queue);
if (!list_empty(&pcdev->capture))
@@ -337,6 +384,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
do_gettimeofday(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
+
+out:
spin_unlock_irqrestore(&pcdev->lock, flags);
return IRQ_HANDLED;
@@ -347,19 +396,14 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- int ret = -EBUSY;
if (pcdev->icd)
- goto err;
+ return -EBUSY;
- dev_info(&icd->dev,
+ dev_info(icd->dev.parent,
"SuperH Mobile CEU driver attached to camera %d\n",
icd->devnum);
- ret = icd->ops->init(icd);
- if (ret)
- goto err;
-
pm_runtime_get_sync(ici->dev);
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
@@ -367,8 +411,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
msleep(1);
pcdev->icd = icd;
-err:
- return ret;
+
+ return 0;
}
/* Called with .video_lock held */
@@ -396,23 +440,149 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
pm_runtime_put_sync(ici->dev);
- icd->ops->release(icd);
-
- dev_info(&icd->dev,
+ dev_info(icd->dev.parent,
"SuperH Mobile CEU driver detached from camera %d\n",
icd->devnum);
pcdev->icd = NULL;
}
+/*
+ * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)"
+ * in SH7722 Hardware Manual
+ */
+static unsigned int size_dst(unsigned int src, unsigned int scale)
+{
+ unsigned int mant_pre = scale >> 12;
+ if (!src || !scale)
+ return src;
+ return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) *
+ mant_pre * 4096 / scale + 1;
+}
+
+static u16 calc_scale(unsigned int src, unsigned int *dst)
+{
+ u16 scale;
+
+ if (src == *dst)
+ return 0;
+
+ scale = (src * 4096 / *dst) & ~7;
+
+ while (scale > 4096 && size_dst(src, scale) < *dst)
+ scale -= 8;
+
+ *dst = size_dst(src, scale);
+
+ return scale;
+}
+
+/* rect is guaranteed to not exceed the scaled camera rectangle */
+static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd,
+ unsigned int out_width,
+ unsigned int out_height)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_rect *rect = &cam->ceu_rect;
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ unsigned int height, width, cdwdr_width, in_width, in_height;
+ unsigned int left_offset, top_offset;
+ u32 camor;
+
+ dev_dbg(icd->dev.parent, "Crop %ux%u@%u:%u\n",
+ rect->width, rect->height, rect->left, rect->top);
+
+ left_offset = rect->left;
+ top_offset = rect->top;
+
+ if (pcdev->image_mode) {
+ in_width = rect->width;
+ if (!pcdev->is_16bit) {
+ in_width *= 2;
+ left_offset *= 2;
+ }
+ width = cdwdr_width = out_width;
+ } else {
+ unsigned int w_factor = (icd->current_fmt->depth + 7) >> 3;
+
+ width = out_width * w_factor / 2;
+
+ if (!pcdev->is_16bit)
+ w_factor *= 2;
+
+ in_width = rect->width * w_factor / 2;
+ left_offset = left_offset * w_factor / 2;
+
+ cdwdr_width = width * 2;
+ }
+
+ height = out_height;
+ in_height = rect->height;
+ if (pcdev->is_interlaced) {
+ height /= 2;
+ in_height /= 2;
+ top_offset /= 2;
+ cdwdr_width *= 2;
+ }
+
+ /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
+ camor = left_offset | (top_offset << 16);
+
+ dev_geo(icd->dev.parent,
+ "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor,
+ (in_height << 16) | in_width, (height << 16) | width,
+ cdwdr_width);
+
+ ceu_write(pcdev, CAMOR, camor);
+ ceu_write(pcdev, CAPWR, (in_height << 16) | in_width);
+ ceu_write(pcdev, CFSZR, (height << 16) | width);
+ ceu_write(pcdev, CDWDR, cdwdr_width);
+}
+
+static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev)
+{
+ u32 capsr = ceu_read(pcdev, CAPSR);
+ ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */
+ return capsr;
+}
+
+static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
+{
+ unsigned long timeout = jiffies + 10 * HZ;
+
+ /*
+ * Wait until the end of the current frame. It can take a long time,
+ * but if it has been aborted by a CAPSR reset, it shoule exit sooner.
+ */
+ while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout))
+ msleep(1);
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(pcdev->ici.v4l2_dev.dev,
+ "Timeout waiting for frame end! Interface problem?\n");
+ return;
+ }
+
+ /* Wait until reset clears, this shall not hang... */
+ while (ceu_read(pcdev, CAPSR) & (1 << 16))
+ udelay(10);
+
+ /* Anything to restore? */
+ if (capsr & ~(1 << 16))
+ ceu_write(pcdev, CAPSR, capsr);
+}
+
static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
__u32 pixfmt)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- int ret, buswidth, width, height, cfszr_width, cdwdr_width;
+ int ret;
unsigned long camera_flags, common_flags, value;
- int yuv_mode, yuv_lineskip;
+ int yuv_lineskip;
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ u32 capsr = capture_save_reset(pcdev);
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
@@ -426,10 +596,10 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
switch (common_flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_8:
- buswidth = 8;
+ pcdev->is_16bit = 0;
break;
case SOCAM_DATAWIDTH_16:
- buswidth = 16;
+ pcdev->is_16bit = 1;
break;
default:
return -EINVAL;
@@ -439,7 +609,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
ceu_write(pcdev, CRCMPR, 0);
value = 0x00000010; /* data fetch by default */
- yuv_mode = yuv_lineskip = 0;
+ yuv_lineskip = 0;
switch (icd->current_fmt->fourcc) {
case V4L2_PIX_FMT_NV12:
@@ -448,8 +618,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
/* fall-through */
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
- yuv_mode = 1;
- switch (pcdev->camera_fmt->fourcc) {
+ switch (cam->camera_fmt->fourcc) {
case V4L2_PIX_FMT_UYVY:
value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
break;
@@ -473,36 +642,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
- value |= buswidth == 16 ? 1 << 12 : 0;
+ value |= pcdev->is_16bit ? 1 << 12 : 0;
ceu_write(pcdev, CAMCR, value);
ceu_write(pcdev, CAPCR, 0x00300000);
ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0);
+ sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height);
mdelay(1);
- if (yuv_mode) {
- width = icd->width * 2;
- width = buswidth == 16 ? width / 2 : width;
- cfszr_width = cdwdr_width = icd->width;
- } else {
- width = icd->width * ((icd->current_fmt->depth + 7) >> 3);
- width = buswidth == 16 ? width / 2 : width;
- cfszr_width = buswidth == 8 ? width / 2 : width;
- cdwdr_width = buswidth == 16 ? width * 2 : width;
- }
-
- height = icd->height;
- if (pcdev->is_interlaced) {
- height /= 2;
- cdwdr_width *= 2;
- }
-
- ceu_write(pcdev, CAMOR, 0);
- ceu_write(pcdev, CAPWR, (height << 16) | width);
- ceu_write(pcdev, CFLCR, 0); /* no scaling */
- ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width);
- ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */
+ ceu_write(pcdev, CFLCR, pcdev->cflcr);
/* A few words about byte order (observed in Big Endian mode)
*
@@ -521,10 +670,15 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */
ceu_write(pcdev, CDOCR, value);
-
- ceu_write(pcdev, CDWDR, cdwdr_width);
ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
+ dev_dbg(icd->dev.parent, "S_FMT successful for %c%c%c%c %ux%u\n",
+ pixfmt & 0xff, (pixfmt >> 8) & 0xff,
+ (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
+ icd->user_width, icd->user_height);
+
+ capture_restore(pcdev, capsr);
+
/* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
return 0;
}
@@ -574,24 +728,35 @@ static const struct soc_camera_data_format sh_mobile_ceu_formats[] = {
static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
struct soc_camera_format_xlate *xlate)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct device *dev = icd->dev.parent;
int ret, k, n;
int formats = 0;
+ struct sh_mobile_ceu_cam *cam;
ret = sh_mobile_ceu_try_bus_param(icd);
if (ret < 0)
return 0;
+ if (!icd->host_priv) {
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam)
+ return -ENOMEM;
+
+ icd->host_priv = cam;
+ } else {
+ cam = icd->host_priv;
+ }
+
/* Beginning of a pass */
if (!idx)
- icd->host_priv = NULL;
+ cam->extra_fmt = NULL;
switch (icd->formats[idx].fourcc) {
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
- if (icd->host_priv)
+ if (cam->extra_fmt)
goto add_single_format;
/*
@@ -603,7 +768,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
* the host_priv pointer and check whether the format you're
* going to add now is already there.
*/
- icd->host_priv = (void *)sh_mobile_ceu_formats;
+ cam->extra_fmt = (void *)sh_mobile_ceu_formats;
n = ARRAY_SIZE(sh_mobile_ceu_formats);
formats += n;
@@ -612,7 +777,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = icd->formats[idx].depth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(dev, "Providing format %s using %s\n",
sh_mobile_ceu_formats[k].name,
icd->formats[idx].name);
}
@@ -625,7 +790,7 @@ add_single_format:
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = icd->formats[idx].depth;
xlate++;
- dev_dbg(ici->dev,
+ dev_dbg(dev,
"Providing format %s in pass-through mode\n",
icd->formats[idx].name);
}
@@ -634,82 +799,714 @@ add_single_format:
return formats;
}
+static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
+{
+ kfree(icd->host_priv);
+ icd->host_priv = NULL;
+}
+
+/* Check if any dimension of r1 is smaller than respective one of r2 */
+static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2)
+{
+ return r1->width < r2->width || r1->height < r2->height;
+}
+
+/* Check if r1 fails to cover r2 */
+static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2)
+{
+ return r1->left > r2->left || r1->top > r2->top ||
+ r1->left + r1->width < r2->left + r2->width ||
+ r1->top + r1->height < r2->top + r2->height;
+}
+
+static unsigned int scale_down(unsigned int size, unsigned int scale)
+{
+ return (size * 4096 + scale / 2) / scale;
+}
+
+static unsigned int scale_up(unsigned int size, unsigned int scale)
+{
+ return (size * scale + 2048) / 4096;
+}
+
+static unsigned int calc_generic_scale(unsigned int input, unsigned int output)
+{
+ return (input * 4096 + output / 2) / output;
+}
+
+static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
+{
+ struct v4l2_crop crop;
+ struct v4l2_cropcap cap;
+ int ret;
+
+ crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_crop, &crop);
+ if (!ret) {
+ *rect = crop.c;
+ return ret;
+ }
+
+ /* Camera driver doesn't support .g_crop(), assume default rectangle */
+ cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ *rect = cap.defrect;
+
+ return ret;
+}
+
+/*
+ * The common for both scaling and cropping iterative approach is:
+ * 1. try if the client can produce exactly what requested by the user
+ * 2. if (1) failed, try to double the client image until we get one big enough
+ * 3. if (2) failed, try to request the maximum image
+ */
+static int client_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop,
+ struct v4l2_crop *cam_crop)
+{
+ struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+ struct device *dev = sd->v4l2_dev->dev;
+ struct v4l2_cropcap cap;
+ int ret;
+ unsigned int width, height;
+
+ v4l2_subdev_call(sd, video, s_crop, crop);
+ ret = client_g_rect(sd, cam_rect);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Now cam_crop contains the current camera input rectangle, and it must
+ * be within camera cropcap bounds
+ */
+ if (!memcmp(rect, cam_rect, sizeof(*rect))) {
+ /* Even if camera S_CROP failed, but camera rectangle matches */
+ dev_dbg(dev, "Camera S_CROP successful for %ux%u@%u:%u\n",
+ rect->width, rect->height, rect->left, rect->top);
+ return 0;
+ }
+
+ /* Try to fix cropping, that camera hasn't managed to set */
+ dev_geo(dev, "Fix camera S_CROP for %ux%u@%u:%u to %ux%u@%u:%u\n",
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top,
+ rect->width, rect->height, rect->left, rect->top);
+
+ /* We need sensor maximum rectangle */
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
+ cap.bounds.width);
+ soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
+ cap.bounds.height);
+
+ /*
+ * Popular special case - some cameras can only handle fixed sizes like
+ * QVGA, VGA,... Take care to avoid infinite loop.
+ */
+ width = max(cam_rect->width, 2);
+ height = max(cam_rect->height, 2);
+
+ while (!ret && (is_smaller(cam_rect, rect) ||
+ is_inside(cam_rect, rect)) &&
+ (cap.bounds.width > width || cap.bounds.height > height)) {
+
+ width *= 2;
+ height *= 2;
+
+ cam_rect->width = width;
+ cam_rect->height = height;
+
+ /*
+ * We do not know what capabilities the camera has to set up
+ * left and top borders. We could try to be smarter in iterating
+ * them, e.g., if camera current left is to the right of the
+ * target left, set it to the middle point between the current
+ * left and minimum left. But that would add too much
+ * complexity: we would have to iterate each border separately.
+ */
+ if (cam_rect->left > rect->left)
+ cam_rect->left = cap.bounds.left;
+
+ if (cam_rect->left + cam_rect->width < rect->left + rect->width)
+ cam_rect->width = rect->left + rect->width -
+ cam_rect->left;
+
+ if (cam_rect->top > rect->top)
+ cam_rect->top = cap.bounds.top;
+
+ if (cam_rect->top + cam_rect->height < rect->top + rect->height)
+ cam_rect->height = rect->top + rect->height -
+ cam_rect->top;
+
+ v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ ret = client_g_rect(sd, cam_rect);
+ dev_geo(dev, "Camera S_CROP %d for %ux%u@%u:%u\n", ret,
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+ }
+
+ /* S_CROP must not modify the rectangle */
+ if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
+ /*
+ * The camera failed to configure a suitable cropping,
+ * we cannot use the current rectangle, set to max
+ */
+ *cam_rect = cap.bounds;
+ v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ ret = client_g_rect(sd, cam_rect);
+ dev_geo(dev, "Camera S_CROP %d for max %ux%u@%u:%u\n", ret,
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+ }
+
+ return ret;
+}
+
+static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect,
+ unsigned int *scale_h, unsigned int *scale_v)
+{
+ struct v4l2_format f;
+ int ret;
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ *scale_h = calc_generic_scale(rect->width, f.fmt.pix.width);
+ *scale_v = calc_generic_scale(rect->height, f.fmt.pix.height);
+
+ return 0;
+}
+
+static int get_camera_subwin(struct soc_camera_device *icd,
+ struct v4l2_rect *cam_subrect,
+ unsigned int cam_hscale, unsigned int cam_vscale)
+{
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_rect *ceu_rect = &cam->ceu_rect;
+
+ if (!ceu_rect->width) {
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ struct v4l2_format f;
+ struct v4l2_pix_format *pix = &f.fmt.pix;
+ int ret;
+ /* First time */
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "camera fmt %ux%u\n", pix->width, pix->height);
+
+ if (pix->width > 2560) {
+ ceu_rect->width = 2560;
+ ceu_rect->left = (pix->width - 2560) / 2;
+ } else {
+ ceu_rect->width = pix->width;
+ ceu_rect->left = 0;
+ }
+
+ if (pix->height > 1920) {
+ ceu_rect->height = 1920;
+ ceu_rect->top = (pix->height - 1920) / 2;
+ } else {
+ ceu_rect->height = pix->height;
+ ceu_rect->top = 0;
+ }
+
+ dev_geo(dev, "initialised CEU rect %ux%u@%u:%u\n",
+ ceu_rect->width, ceu_rect->height,
+ ceu_rect->left, ceu_rect->top);
+ }
+
+ cam_subrect->width = scale_up(ceu_rect->width, cam_hscale);
+ cam_subrect->left = scale_up(ceu_rect->left, cam_hscale);
+ cam_subrect->height = scale_up(ceu_rect->height, cam_vscale);
+ cam_subrect->top = scale_up(ceu_rect->top, cam_vscale);
+
+ return 0;
+}
+
+static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f,
+ bool ceu_can_scale)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ unsigned int width = pix->width, height = pix->height, tmp_w, tmp_h;
+ unsigned int max_width, max_height;
+ struct v4l2_cropcap cap;
+ int ret;
+
+ cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ max_width = min(cap.bounds.width, 2560);
+ max_height = min(cap.bounds.height, 1920);
+
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "camera scaled to %ux%u\n", pix->width, pix->height);
+
+ if ((width == pix->width && height == pix->height) || !ceu_can_scale)
+ return 0;
+
+ /* Camera set a format, but geometry is not precise, try to improve */
+ tmp_w = pix->width;
+ tmp_h = pix->height;
+
+ /* width <= max_width && height <= max_height - guaranteed by try_fmt */
+ while ((width > tmp_w || height > tmp_h) &&
+ tmp_w < max_width && tmp_h < max_height) {
+ tmp_w = min(2 * tmp_w, max_width);
+ tmp_h = min(2 * tmp_h, max_height);
+ pix->width = tmp_w;
+ pix->height = tmp_h;
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
+ dev_geo(dev, "Camera scaled to %ux%u\n",
+ pix->width, pix->height);
+ if (ret < 0) {
+ /* This shouldn't happen */
+ dev_err(dev, "Client failed to set format: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @rect - camera cropped rectangle
+ * @sub_rect - CEU cropped rectangle, mapped back to camera input area
+ * @ceu_rect - on output calculated CEU crop rectangle
+ */
+static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect,
+ struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect,
+ struct v4l2_format *f, bool ceu_can_scale)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct device *dev = icd->dev.parent;
+ struct v4l2_format f_tmp = *f;
+ struct v4l2_pix_format *pix_tmp = &f_tmp.fmt.pix;
+ unsigned int scale_h, scale_v;
+ int ret;
+
+ /* 5. Apply iterative camera S_FMT for camera user window. */
+ ret = client_s_fmt(icd, &f_tmp, ceu_can_scale);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "5: camera scaled to %ux%u\n",
+ pix_tmp->width, pix_tmp->height);
+
+ /* 6. Retrieve camera output window (g_fmt) */
+
+ /* unneeded - it is already in "f_tmp" */
+
+ /* 7. Calculate new camera scales. */
+ ret = get_camera_scales(sd, rect, &scale_h, &scale_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v);
+
+ cam->cam_width = pix_tmp->width;
+ cam->cam_height = pix_tmp->height;
+ f->fmt.pix.width = pix_tmp->width;
+ f->fmt.pix.height = pix_tmp->height;
+
+ /*
+ * 8. Calculate new CEU crop - apply camera scales to previously
+ * calculated "effective" crop.
+ */
+ ceu_rect->left = scale_down(sub_rect->left, scale_h);
+ ceu_rect->width = scale_down(sub_rect->width, scale_h);
+ ceu_rect->top = scale_down(sub_rect->top, scale_v);
+ ceu_rect->height = scale_down(sub_rect->height, scale_v);
+
+ dev_geo(dev, "8: new CEU rect %ux%u@%u:%u\n",
+ ceu_rect->width, ceu_rect->height,
+ ceu_rect->left, ceu_rect->top);
+
+ return 0;
+}
+
+/* Get combined scales */
+static int get_scales(struct soc_camera_device *icd,
+ unsigned int *scale_h, unsigned int *scale_v)
+{
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_crop cam_crop;
+ unsigned int width_in, height_in;
+ int ret;
+
+ cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = client_g_rect(sd, &cam_crop.c);
+ if (ret < 0)
+ return ret;
+
+ ret = get_camera_scales(sd, &cam_crop.c, scale_h, scale_v);
+ if (ret < 0)
+ return ret;
+
+ width_in = scale_up(cam->ceu_rect.width, *scale_h);
+ height_in = scale_up(cam->ceu_rect.height, *scale_v);
+
+ *scale_h = calc_generic_scale(cam->ceu_rect.width, icd->user_width);
+ *scale_v = calc_generic_scale(cam->ceu_rect.height, icd->user_height);
+
+ return 0;
+}
+
+/*
+ * CEU can scale and crop, but we don't want to waste bandwidth and kill the
+ * framerate by always requesting the maximum image from the client. See
+ * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of
+ * scaling and cropping algorithms and for the meaning of referenced here steps.
+ */
static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
- return icd->ops->set_crop(icd, rect);
+ struct v4l2_rect *rect = &a->c;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ struct v4l2_crop cam_crop;
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ struct v4l2_format f;
+ struct v4l2_pix_format *pix = &f.fmt.pix;
+ unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v,
+ out_width, out_height;
+ u32 capsr, cflcr;
+ int ret;
+
+ /* 1. Calculate current combined scales. */
+ ret = get_scales(icd, &scale_comb_h, &scale_comb_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "1: combined scales %u:%u\n", scale_comb_h, scale_comb_v);
+
+ /* 2. Apply iterative camera S_CROP for new input window. */
+ ret = client_s_crop(sd, a, &cam_crop);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "2: camera cropped to %ux%u@%u:%u\n",
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+
+ /* On success cam_crop contains current camera crop */
+
+ /*
+ * 3. If old combined scales applied to new crop produce an impossible
+ * user window, adjust scales to produce nearest possible window.
+ */
+ out_width = scale_down(rect->width, scale_comb_h);
+ out_height = scale_down(rect->height, scale_comb_v);
+
+ if (out_width > 2560)
+ out_width = 2560;
+ else if (out_width < 2)
+ out_width = 2;
+
+ if (out_height > 1920)
+ out_height = 1920;
+ else if (out_height < 4)
+ out_height = 4;
+
+ dev_geo(dev, "3: Adjusted output %ux%u\n", out_width, out_height);
+
+ /* 4. Use G_CROP to retrieve actual input window: already in cam_crop */
+
+ /*
+ * 5. Using actual input window and calculated combined scales calculate
+ * camera target output window.
+ */
+ pix->width = scale_down(cam_rect->width, scale_comb_h);
+ pix->height = scale_down(cam_rect->height, scale_comb_v);
+
+ dev_geo(dev, "5: camera target %ux%u\n", pix->width, pix->height);
+
+ /* 6. - 9. */
+ pix->pixelformat = cam->camera_fmt->fourcc;
+ pix->colorspace = cam->camera_fmt->colorspace;
+
+ capsr = capture_save_reset(pcdev);
+ dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
+
+ /* Make relative to camera rectangle */
+ rect->left -= cam_rect->left;
+ rect->top -= cam_rect->top;
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = client_scale(icd, cam_rect, rect, ceu_rect, &f,
+ pcdev->image_mode && !pcdev->is_interlaced);
+
+ dev_geo(dev, "6-9: %d\n", ret);
+
+ /* 10. Use CEU cropping to crop to the new window. */
+ sh_mobile_ceu_set_rect(icd, out_width, out_height);
+
+ dev_geo(dev, "10: CEU cropped to %ux%u@%u:%u\n",
+ ceu_rect->width, ceu_rect->height,
+ ceu_rect->left, ceu_rect->top);
+
+ /*
+ * 11. Calculate CEU scales from camera scales from results of (10) and
+ * user window from (3)
+ */
+ scale_ceu_h = calc_scale(ceu_rect->width, &out_width);
+ scale_ceu_v = calc_scale(ceu_rect->height, &out_height);
+
+ dev_geo(dev, "11: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v);
+
+ /* 12. Apply CEU scales. */
+ cflcr = scale_ceu_h | (scale_ceu_v << 16);
+ if (cflcr != pcdev->cflcr) {
+ pcdev->cflcr = cflcr;
+ ceu_write(pcdev, CFLCR, cflcr);
+ }
+
+ /* Restore capture */
+ if (pcdev->active)
+ capsr |= 1;
+ capture_restore(pcdev, capsr);
+
+ icd->user_width = out_width;
+ icd->user_height = out_height;
+
+ /* Even if only camera cropping succeeded */
+ return ret;
}
+/* Similar to set_crop multistage iterative algorithm */
static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- __u32 pixfmt = f->fmt.pix.pixelformat;
- const struct soc_camera_format_xlate *xlate;
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_format cam_f = *f;
+ struct v4l2_pix_format *cam_pix = &cam_f.fmt.pix;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ __u32 pixfmt = pix->pixelformat;
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_crop cam_crop;
+ struct v4l2_rect *cam_rect = &cam_crop.c, cam_subrect, ceu_rect;
+ unsigned int scale_cam_h, scale_cam_v;
+ u16 scale_v, scale_h;
int ret;
+ bool is_interlaced, image_mode;
+
+ switch (pix->field) {
+ case V4L2_FIELD_INTERLACED:
+ is_interlaced = true;
+ break;
+ case V4L2_FIELD_ANY:
+ default:
+ pix->field = V4L2_FIELD_NONE;
+ /* fall-through */
+ case V4L2_FIELD_NONE:
+ is_interlaced = false;
+ break;
+ }
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
- cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
- ret = icd->ops->set_fmt(icd, &cam_f);
+ /* 1. Calculate current camera scales. */
+ cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (!ret) {
- icd->buswidth = xlate->buswidth;
- icd->current_fmt = xlate->host_fmt;
- pcdev->camera_fmt = xlate->cam_fmt;
+ ret = client_g_rect(sd, cam_rect);
+ if (ret < 0)
+ return ret;
+
+ ret = get_camera_scales(sd, cam_rect, &scale_cam_h, &scale_cam_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "1: camera scales %u:%u\n", scale_cam_h, scale_cam_v);
+
+ /*
+ * 2. Calculate "effective" input crop (sensor subwindow) - CEU crop
+ * scaled back at current camera scales onto input window.
+ */
+ ret = get_camera_subwin(icd, &cam_subrect, scale_cam_h, scale_cam_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
+ cam_subrect.width, cam_subrect.height,
+ cam_subrect.left, cam_subrect.top);
+
+ /*
+ * 3. Calculate new combined scales from "effective" input window to
+ * requested user window.
+ */
+ scale_h = calc_generic_scale(cam_subrect.width, pix->width);
+ scale_v = calc_generic_scale(cam_subrect.height, pix->height);
+
+ dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
+
+ /*
+ * 4. Calculate camera output window by applying combined scales to real
+ * input window.
+ */
+ cam_pix->width = scale_down(cam_rect->width, scale_h);
+ cam_pix->height = scale_down(cam_rect->height, scale_v);
+ cam_pix->pixelformat = xlate->cam_fmt->fourcc;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ image_mode = true;
+ break;
+ default:
+ image_mode = false;
}
- return ret;
+ dev_geo(dev, "4: camera output %ux%u\n",
+ cam_pix->width, cam_pix->height);
+
+ /* 5. - 9. */
+ ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &cam_f,
+ image_mode && !is_interlaced);
+
+ dev_geo(dev, "5-9: client scale %d\n", ret);
+
+ /* Done with the camera. Now see if we can improve the result */
+
+ dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
+ ret, cam_pix->width, cam_pix->height, pix->width, pix->height);
+ if (ret < 0)
+ return ret;
+
+ /* 10. Use CEU scaling to scale to the requested user window. */
+
+ /* We cannot scale up */
+ if (pix->width > cam_pix->width)
+ pix->width = cam_pix->width;
+ if (pix->width > ceu_rect.width)
+ pix->width = ceu_rect.width;
+
+ if (pix->height > cam_pix->height)
+ pix->height = cam_pix->height;
+ if (pix->height > ceu_rect.height)
+ pix->height = ceu_rect.height;
+
+ /* Let's rock: scale pix->{width x height} down to width x height */
+ scale_h = calc_scale(ceu_rect.width, &pix->width);
+ scale_v = calc_scale(ceu_rect.height, &pix->height);
+
+ dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n",
+ ceu_rect.width, scale_h, pix->width,
+ ceu_rect.height, scale_v, pix->height);
+
+ pcdev->cflcr = scale_h | (scale_v << 16);
+
+ icd->buswidth = xlate->buswidth;
+ icd->current_fmt = xlate->host_fmt;
+ cam->camera_fmt = xlate->cam_fmt;
+ cam->ceu_rect = ceu_rect;
+
+ pcdev->is_interlaced = is_interlaced;
+ pcdev->image_mode = image_mode;
+
+ return 0;
}
static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct sh_mobile_ceu_dev *pcdev = ici->priv;
const struct soc_camera_format_xlate *xlate;
- __u32 pixfmt = f->fmt.pix.pixelformat;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ __u32 pixfmt = pix->pixelformat;
+ int width, height;
int ret;
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
return -EINVAL;
}
/* FIXME: calculate using depth and bus width */
- v4l_bound_align_image(&f->fmt.pix.width, 2, 2560, 1,
- &f->fmt.pix.height, 4, 1920, 2, 0);
+ v4l_bound_align_image(&pix->width, 2, 2560, 1,
+ &pix->height, 4, 1920, 2, 0);
+
+ width = pix->width;
+ height = pix->height;
- f->fmt.pix.bytesperline = f->fmt.pix.width *
+ pix->bytesperline = pix->width *
DIV_ROUND_UP(xlate->host_fmt->depth, 8);
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ pix->sizeimage = pix->height * pix->bytesperline;
+
+ pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- ret = icd->ops->try_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
+ pix->pixelformat = pixfmt;
if (ret < 0)
return ret;
- switch (f->fmt.pix.field) {
- case V4L2_FIELD_INTERLACED:
- pcdev->is_interlaced = 1;
- break;
- case V4L2_FIELD_ANY:
- f->fmt.pix.field = V4L2_FIELD_NONE;
- /* fall-through */
- case V4L2_FIELD_NONE:
- pcdev->is_interlaced = 0;
- break;
- default:
- ret = -EINVAL;
- break;
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ /* FIXME: check against rect_max after converting soc-camera */
+ /* We can scale precisely, need a bigger image from camera */
+ if (pix->width < width || pix->height < height) {
+ int tmp_w = pix->width, tmp_h = pix->height;
+ pix->width = 2560;
+ pix->height = 1920;
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
+ if (ret < 0) {
+ /* Shouldn't actually happen... */
+ dev_err(icd->dev.parent,
+ "FIXME: try_fmt() returned %d\n", ret);
+ pix->width = tmp_w;
+ pix->height = tmp_h;
+ }
+ }
+ if (pix->width > width)
+ pix->width = width;
+ if (pix->height > height)
+ pix->height = height;
}
return ret;
@@ -769,7 +1566,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
videobuf_queue_dma_contig_init(q,
&sh_mobile_ceu_videobuf_ops,
- ici->dev, &pcdev->lock,
+ icd->dev.parent, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
pcdev->is_interlaced ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
@@ -777,22 +1574,76 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
icd);
}
+static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ u32 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_SHARPNESS:
+ val = ceu_read(pcdev, CLFCR);
+ ctrl->value = val ^ 1;
+ return 0;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_SHARPNESS:
+ switch (icd->current_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ ceu_write(pcdev, CLFCR, !ctrl->value);
+ return 0;
+ }
+ return -EINVAL;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Low-pass filter",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.owner = THIS_MODULE,
.add = sh_mobile_ceu_add_device,
.remove = sh_mobile_ceu_remove_device,
.get_formats = sh_mobile_ceu_get_formats,
+ .put_formats = sh_mobile_ceu_put_formats,
.set_crop = sh_mobile_ceu_set_crop,
.set_fmt = sh_mobile_ceu_set_fmt,
.try_fmt = sh_mobile_ceu_try_fmt,
+ .set_ctrl = sh_mobile_ceu_set_ctrl,
+ .get_ctrl = sh_mobile_ceu_get_ctrl,
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
.set_bus_param = sh_mobile_ceu_set_bus_param,
.init_videobuf = sh_mobile_ceu_init_videobuf,
+ .controls = sh_mobile_ceu_controls,
+ .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls),
};
-static int sh_mobile_ceu_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
{
struct sh_mobile_ceu_dev *pcdev;
struct resource *res;
@@ -865,7 +1716,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
pm_runtime_resume(&pdev->dev);
pcdev->ici.priv = pcdev;
- pcdev->ici.dev = &pdev->dev;
+ pcdev->ici.v4l2_dev.dev = &pdev->dev;
pcdev->ici.nr = pdev->id;
pcdev->ici.drv_name = dev_name(&pdev->dev);
pcdev->ici.ops = &sh_mobile_ceu_host_ops;
@@ -889,7 +1740,7 @@ exit:
return err;
}
-static int sh_mobile_ceu_remove(struct platform_device *pdev)
+static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
{
struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
@@ -927,7 +1778,7 @@ static struct platform_driver sh_mobile_ceu_driver = {
.pm = &sh_mobile_ceu_dev_pm_ops,
},
.probe = sh_mobile_ceu_probe,
- .remove = sh_mobile_ceu_remove,
+ .remove = __exit_p(sh_mobile_ceu_remove),
};
static int __init sh_mobile_ceu_init(void)
@@ -946,3 +1797,4 @@ module_exit(sh_mobile_ceu_exit);
MODULE_DESCRIPTION("SuperH Mobile CEU driver");
MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh_mobile_ceu");
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 9f5ae8167855..59aa7a3694c2 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -21,15 +21,15 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/vmalloc.h>
#include <media/soc_camera.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-dev.h>
#include <media/videobuf-core.h>
/* Default to VGA resolution */
@@ -38,7 +38,7 @@
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
-static DEFINE_MUTEX(list_lock);
+static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
const struct soc_camera_data_format *soc_camera_format_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
@@ -152,12 +152,9 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- int ret = 0;
-
- if (icd->ops->set_std)
- ret = icd->ops->set_std(icd, a);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return ret;
+ return v4l2_subdev_call(sd, core, s_std, *a);
}
static int soc_camera_reqbufs(struct file *file, void *priv,
@@ -170,8 +167,6 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);
-
ret = videobuf_reqbufs(&icf->vb_vidq, p);
if (ret < 0)
return ret;
@@ -209,10 +204,11 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
+/* Always entered with .video_lock held */
static int soc_camera_init_user_formats(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- int i, fmts = 0;
+ int i, fmts = 0, ret;
if (!ici->ops->get_formats)
/*
@@ -225,8 +221,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
* First pass - only count formats this host-sensor
* configuration can provide
*/
- for (i = 0; i < icd->num_formats; i++)
- fmts += ici->ops->get_formats(icd, i, NULL);
+ for (i = 0; i < icd->num_formats; i++) {
+ ret = ici->ops->get_formats(icd, i, NULL);
+ if (ret < 0)
+ return ret;
+ fmts += ret;
+ }
if (!fmts)
return -ENXIO;
@@ -248,20 +248,39 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
icd->user_formats[i].cam_fmt = icd->formats + i;
icd->user_formats[i].buswidth = icd->formats[i].depth;
} else {
- fmts += ici->ops->get_formats(icd, i,
- &icd->user_formats[fmts]);
+ ret = ici->ops->get_formats(icd, i,
+ &icd->user_formats[fmts]);
+ if (ret < 0)
+ goto egfmt;
+ fmts += ret;
}
icd->current_fmt = icd->user_formats[0].host_fmt;
return 0;
+
+egfmt:
+ icd->num_user_formats = 0;
+ vfree(icd->user_formats);
+ return ret;
}
+/* Always entered with .video_lock held */
static void soc_camera_free_user_formats(struct soc_camera_device *icd)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+
+ if (ici->ops->put_formats)
+ ici->ops->put_formats(icd);
+ icd->current_fmt = NULL;
+ icd->num_user_formats = 0;
vfree(icd->user_formats);
+ icd->user_formats = NULL;
}
+#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
+ ((x) >> 24) & 0xff
+
/* Called with .vb_lock held */
static int soc_camera_set_fmt(struct soc_camera_file *icf,
struct v4l2_format *f)
@@ -271,6 +290,9 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
+ dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n",
+ pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
/* We always call try_fmt() before set_fmt() or set_crop() */
ret = ici->ops->try_fmt(icd, f);
if (ret < 0)
@@ -281,13 +303,13 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
return ret;
} else if (!icd->current_fmt ||
icd->current_fmt->fourcc != pix->pixelformat) {
- dev_err(ici->dev,
+ dev_err(&icd->dev,
"Host driver hasn't set up current format correctly!\n");
return -EINVAL;
}
- icd->width = pix->width;
- icd->height = pix->height;
+ icd->user_width = pix->width;
+ icd->user_height = pix->height;
icf->vb_vidq.field =
icd->field = pix->field;
@@ -296,7 +318,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
f->type);
dev_dbg(&icd->dev, "set width: %d height: %d\n",
- icd->width, icd->height);
+ icd->user_width, icd->user_height);
/* set physical bus parameters */
return ici->ops->set_bus_param(icd, pix->pixelformat);
@@ -304,30 +326,24 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
static int soc_camera_open(struct file *file)
{
- struct video_device *vdev;
- struct soc_camera_device *icd;
+ struct video_device *vdev = video_devdata(file);
+ struct soc_camera_device *icd = container_of(vdev->parent,
+ struct soc_camera_device,
+ dev);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
struct soc_camera_host *ici;
struct soc_camera_file *icf;
int ret;
- icf = vmalloc(sizeof(*icf));
- if (!icf)
- return -ENOMEM;
-
- /*
- * It is safe to dereference these pointers now as long as a user has
- * the video device open - we are protected by the held cdev reference.
- */
+ if (!icd->ops)
+ /* No device driver attached */
+ return -ENODEV;
- vdev = video_devdata(file);
- icd = container_of(vdev->parent, struct soc_camera_device, dev);
ici = to_soc_camera_host(icd->dev.parent);
- if (!try_module_get(icd->ops->owner)) {
- dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
- ret = -EINVAL;
- goto emgd;
- }
+ icf = vmalloc(sizeof(*icf));
+ if (!icf)
+ return -ENOMEM;
if (!try_module_get(ici->ops->owner)) {
dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
@@ -335,7 +351,10 @@ static int soc_camera_open(struct file *file)
goto emgi;
}
- /* Protect against icd->remove() until we module_get() both drivers. */
+ /*
+ * Protect against icd->ops->remove() until we module_get() both
+ * drivers.
+ */
mutex_lock(&icd->video_lock);
icf->icd = icd;
@@ -347,14 +366,24 @@ static int soc_camera_open(struct file *file)
struct v4l2_format f = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.fmt.pix = {
- .width = icd->width,
- .height = icd->height,
+ .width = icd->user_width,
+ .height = icd->user_height,
.field = icd->field,
.pixelformat = icd->current_fmt->fourcc,
.colorspace = icd->current_fmt->colorspace,
},
};
+ if (icl->power) {
+ ret = icl->power(icd->pdev, 1);
+ if (ret < 0)
+ goto epower;
+ }
+
+ /* The camera could have been already on, try to reset */
+ if (icl->reset)
+ icl->reset(icd->pdev);
+
ret = ici->ops->add(icd);
if (ret < 0) {
dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
@@ -367,28 +396,29 @@ static int soc_camera_open(struct file *file)
goto esfmt;
}
- mutex_unlock(&icd->video_lock);
-
file->private_data = icf;
dev_dbg(&icd->dev, "camera device open\n");
ici->ops->init_videobuf(&icf->vb_vidq, icd);
+ mutex_unlock(&icd->video_lock);
+
return 0;
/*
- * First three errors are entered with the .video_lock held
+ * First five errors are entered with the .video_lock held
* and use_count == 1
*/
esfmt:
ici->ops->remove(icd);
eiciadd:
+ if (icl->power)
+ icl->power(icd->pdev, 0);
+epower:
icd->use_count--;
mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
emgi:
- module_put(icd->ops->owner);
-emgd:
vfree(icf);
return ret;
}
@@ -398,21 +428,24 @@ static int soc_camera_close(struct file *file)
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct video_device *vdev = icd->vdev;
mutex_lock(&icd->video_lock);
icd->use_count--;
- if (!icd->use_count)
+ if (!icd->use_count) {
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
ici->ops->remove(icd);
+ if (icl->power)
+ icl->power(icd->pdev, 0);
+ }
mutex_unlock(&icd->video_lock);
- module_put(icd->ops->owner);
module_put(ici->ops->owner);
vfree(icf);
- dev_dbg(vdev->parent, "camera device close\n");
+ dev_dbg(&icd->dev, "camera device close\n");
return 0;
}
@@ -422,10 +455,9 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- struct video_device *vdev = icd->vdev;
int err = -EINVAL;
- dev_err(vdev->parent, "camera device read not implemented\n");
+ dev_err(&icd->dev, "camera device read not implemented\n");
return err;
}
@@ -483,8 +515,8 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
mutex_lock(&icf->vb_vidq.vb_lock);
- if (videobuf_queue_is_busy(&icf->vb_vidq)) {
- dev_err(&icd->dev, "S_FMT denied: queue busy\n");
+ if (icf->vb_vidq.bufs[0]) {
+ dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
ret = -EBUSY;
goto unlock;
}
@@ -525,8 +557,8 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- pix->width = icd->width;
- pix->height = icd->height;
+ pix->width = icd->user_width;
+ pix->height = icd->user_height;
pix->field = icf->vb_vidq.field;
pix->pixelformat = icd->current_fmt->fourcc;
pix->bytesperline = pix->width *
@@ -555,18 +587,17 @@ static int soc_camera_streamon(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __func__);
-
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
mutex_lock(&icd->video_lock);
- icd->ops->start_capture(icd);
+ v4l2_subdev_call(sd, video, s_stream, 1);
/* This calls buf_queue from host driver's videobuf_queue_ops */
ret = videobuf_streamon(&icf->vb_vidq);
@@ -581,11 +612,10 @@ static int soc_camera_streamoff(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __func__);
-
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -595,7 +625,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
* remaining buffers. When the last buffer is freed, stop capture */
videobuf_streamoff(&icf->vb_vidq);
- icd->ops->stop_capture(icd);
+ v4l2_subdev_call(sd, video, s_stream, 0);
mutex_unlock(&icd->video_lock);
@@ -607,6 +637,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int i;
WARN_ON(priv != file->private_data);
@@ -614,6 +645,15 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
if (!qc->id)
return -EINVAL;
+ /* First check host controls */
+ for (i = 0; i < ici->ops->num_controls; i++)
+ if (qc->id == ici->ops->controls[i].id) {
+ memcpy(qc, &(ici->ops->controls[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ /* Then device controls */
for (i = 0; i < icd->ops->num_controls; i++)
if (qc->id == icd->ops->controls[i].id) {
memcpy(qc, &(icd->ops->controls[i]),
@@ -629,25 +669,19 @@ static int soc_camera_g_ctrl(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ int ret;
WARN_ON(priv != file->private_data);
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- if (icd->gain == (unsigned short)~0)
- return -EINVAL;
- ctrl->value = icd->gain;
- return 0;
- case V4L2_CID_EXPOSURE:
- if (icd->exposure == (unsigned short)~0)
- return -EINVAL;
- ctrl->value = icd->exposure;
- return 0;
+ if (ici->ops->get_ctrl) {
+ ret = ici->ops->get_ctrl(icd, ctrl);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
}
- if (icd->ops->get_control)
- return icd->ops->get_control(icd, ctrl);
- return -EINVAL;
+ return v4l2_subdev_call(sd, core, g_ctrl, ctrl);
}
static int soc_camera_s_ctrl(struct file *file, void *priv,
@@ -655,12 +689,19 @@ static int soc_camera_s_ctrl(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ int ret;
WARN_ON(priv != file->private_data);
- if (icd->ops->set_control)
- return icd->ops->set_control(icd, ctrl);
- return -EINVAL;
+ if (ici->ops->set_ctrl) {
+ ret = ici->ops->set_ctrl(icd, ctrl);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
+ }
+
+ return v4l2_subdev_call(sd, core, s_ctrl, ctrl);
}
static int soc_camera_cropcap(struct file *file, void *fh,
@@ -668,20 +709,9 @@ static int soc_camera_cropcap(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->bounds.left = icd->x_min;
- a->bounds.top = icd->y_min;
- a->bounds.width = icd->width_max;
- a->bounds.height = icd->height_max;
- a->defrect.left = icd->x_min;
- a->defrect.top = icd->y_min;
- a->defrect.width = DEFAULT_WIDTH;
- a->defrect.height = DEFAULT_HEIGHT;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
+ return ici->ops->cropcap(icd, a);
}
static int soc_camera_g_crop(struct file *file, void *fh,
@@ -689,36 +719,53 @@ static int soc_camera_g_crop(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int ret;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->c.left = icd->x_current;
- a->c.top = icd->y_current;
- a->c.width = icd->width;
- a->c.height = icd->height;
+ mutex_lock(&icf->vb_vidq.vb_lock);
+ ret = ici->ops->get_crop(icd, a);
+ mutex_unlock(&icf->vb_vidq.vb_lock);
- return 0;
+ return ret;
}
+/*
+ * According to the V4L2 API, drivers shall not update the struct v4l2_crop
+ * argument with the actual geometry, instead, the user shall use G_CROP to
+ * retrieve it. However, we expect camera host and client drivers to update
+ * the argument, which we then use internally, but do not return to the user.
+ */
static int soc_camera_s_crop(struct file *file, void *fh,
struct v4l2_crop *a)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop current_crop;
int ret;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
+ rect->width, rect->height, rect->left, rect->top);
+
/* Cropping is allowed during a running capture, guard consistency */
mutex_lock(&icf->vb_vidq.vb_lock);
- ret = ici->ops->set_crop(icd, &a->c);
- if (!ret) {
- icd->width = a->c.width;
- icd->height = a->c.height;
- icd->x_current = a->c.left;
- icd->y_current = a->c.top;
+ /* If get_crop fails, we'll let host and / or client drivers decide */
+ ret = ici->ops->get_crop(icd, &current_crop);
+
+ /* Prohibit window size change with initialised buffers */
+ if (icf->vb_vidq.bufs[0] && !ret &&
+ (a->c.width != current_crop.c.width ||
+ a->c.height != current_crop.c.height)) {
+ dev_err(&icd->dev,
+ "S_CROP denied: queue initialised and sizes differ\n");
+ ret = -EBUSY;
+ } else {
+ ret = ici->ops->set_crop(icd, a);
}
mutex_unlock(&icf->vb_vidq.vb_lock);
@@ -731,11 +778,9 @@ static int soc_camera_g_chip_ident(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- if (!icd->ops->get_chip_id)
- return -EINVAL;
-
- return icd->ops->get_chip_id(icd, id);
+ return v4l2_subdev_call(sd, core, g_chip_ident, id);
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -744,11 +789,9 @@ static int soc_camera_g_register(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- if (!icd->ops->get_register)
- return -EINVAL;
-
- return icd->ops->get_register(icd, reg);
+ return v4l2_subdev_call(sd, core, g_register, reg);
}
static int soc_camera_s_register(struct file *file, void *fh,
@@ -756,37 +799,12 @@ static int soc_camera_s_register(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- if (!icd->ops->set_register)
- return -EINVAL;
-
- return icd->ops->set_register(icd, reg);
+ return v4l2_subdev_call(sd, core, s_register, reg);
}
#endif
-static int device_register_link(struct soc_camera_device *icd)
-{
- int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
-
- if (!ret)
- ret = device_register(&icd->dev);
-
- if (ret < 0) {
- /* Prevent calling device_unregister() */
- icd->dev.parent = NULL;
- dev_err(&icd->dev, "Cannot register device: %d\n", ret);
- /* Even if probe() was unsuccessful for all registered drivers,
- * device_register() returns 0, and we add the link, just to
- * document this camera's control device */
- } else if (icd->control)
- /* Have to sysfs_remove_link() before device_unregister()? */
- if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
- "control"))
- dev_warn(&icd->dev,
- "Failed creating the control symlink\n");
- return ret;
-}
-
/* So far this function cannot fail */
static void scan_add_host(struct soc_camera_host *ici)
{
@@ -796,106 +814,193 @@ static void scan_add_host(struct soc_camera_host *ici)
list_for_each_entry(icd, &devices, list) {
if (icd->iface == ici->nr) {
- icd->dev.parent = ici->dev;
- device_register_link(icd);
+ int ret;
+ icd->dev.parent = ici->v4l2_dev.dev;
+ dev_set_name(&icd->dev, "%u-%u", icd->iface,
+ icd->devnum);
+ ret = device_register(&icd->dev);
+ if (ret < 0) {
+ icd->dev.parent = NULL;
+ dev_err(&icd->dev,
+ "Cannot register device: %d\n", ret);
+ }
}
}
mutex_unlock(&list_lock);
}
-/* return: 0 if no match found or a match found and
- * device_register() successful, error code otherwise */
-static int scan_add_device(struct soc_camera_device *icd)
+#ifdef CONFIG_I2C_BOARDINFO
+static int soc_camera_init_i2c(struct soc_camera_device *icd,
+ struct soc_camera_link *icl)
{
- struct soc_camera_host *ici;
- int ret = 0;
+ struct i2c_client *client;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
+ struct v4l2_subdev *subdev;
+ int ret;
- mutex_lock(&list_lock);
+ if (!adap) {
+ ret = -ENODEV;
+ dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n",
+ icl->i2c_adapter_id);
+ goto ei2cga;
+ }
- list_add_tail(&icd->list, &devices);
+ icl->board_info->platform_data = icd;
- /* Watch out for class_for_each_device / class_find_device API by
- * Dave Young <hidave.darkstar@gmail.com> */
- list_for_each_entry(ici, &hosts, list) {
- if (icd->iface == ici->nr) {
- ret = 1;
- icd->dev.parent = ici->dev;
- break;
- }
+ subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
+ icl->module_name, icl->board_info, NULL);
+ if (!subdev) {
+ ret = -ENOMEM;
+ goto ei2cnd;
}
- mutex_unlock(&list_lock);
+ client = subdev->priv;
- if (ret)
- ret = device_register_link(icd);
+ /* Use to_i2c_client(dev) to recover the i2c client */
+ dev_set_drvdata(&icd->dev, &client->dev);
+ return 0;
+ei2cnd:
+ i2c_put_adapter(adap);
+ei2cga:
return ret;
}
+static void soc_camera_free_i2c(struct soc_camera_device *icd)
+{
+ struct i2c_client *client =
+ to_i2c_client(to_soc_camera_control(icd));
+ dev_set_drvdata(&icd->dev, NULL);
+ v4l2_device_unregister_subdev(i2c_get_clientdata(client));
+ i2c_unregister_device(client);
+ i2c_put_adapter(client->adapter);
+}
+#else
+#define soc_camera_init_i2c(icd, icl) (-ENODEV)
+#define soc_camera_free_i2c(icd) do {} while (0)
+#endif
+
+static int soc_camera_video_start(struct soc_camera_device *icd);
+static int video_dev_create(struct soc_camera_device *icd);
+/* Called during host-driver probe */
static int soc_camera_probe(struct device *dev)
{
struct soc_camera_device *icd = to_soc_camera_dev(dev);
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct device *control = NULL;
+ struct v4l2_subdev *sd;
+ struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
int ret;
- /*
- * Possible race scenario:
- * modprobe <camera-host-driver> triggers __func__
- * at this moment respective <camera-sensor-driver> gets rmmod'ed
- * to protect take module references.
- */
+ dev_info(dev, "Probing %s\n", dev_name(dev));
- if (!try_module_get(icd->ops->owner)) {
- dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
- ret = -EINVAL;
- goto emgd;
+ if (icl->power) {
+ ret = icl->power(icd->pdev, 1);
+ if (ret < 0) {
+ dev_err(dev,
+ "Platform failed to power-on the camera.\n");
+ goto epower;
+ }
}
- if (!try_module_get(ici->ops->owner)) {
- dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+ /* The camera could have been already on, try to reset */
+ if (icl->reset)
+ icl->reset(icd->pdev);
+
+ ret = ici->ops->add(icd);
+ if (ret < 0)
+ goto eadd;
+
+ /* Must have icd->vdev before registering the device */
+ ret = video_dev_create(icd);
+ if (ret < 0)
+ goto evdc;
+
+ /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
+ if (icl->board_info) {
+ ret = soc_camera_init_i2c(icd, icl);
+ if (ret < 0)
+ goto eadddev;
+ } else if (!icl->add_device || !icl->del_device) {
ret = -EINVAL;
- goto emgi;
+ goto eadddev;
+ } else {
+ if (icl->module_name)
+ ret = request_module(icl->module_name);
+
+ ret = icl->add_device(icl, &icd->dev);
+ if (ret < 0)
+ goto eadddev;
+
+ /*
+ * FIXME: this is racy, have to use driver-binding notification,
+ * when it is available
+ */
+ control = to_soc_camera_control(icd);
+ if (!control || !control->driver || !dev_get_drvdata(control) ||
+ !try_module_get(control->driver->owner)) {
+ icl->del_device(icl);
+ goto enodrv;
+ }
}
+ /* At this point client .probe() should have run already */
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eiufmt;
+
+ icd->field = V4L2_FIELD_ANY;
+
+ /* ..._video_start() will create a device node, so we have to protect */
mutex_lock(&icd->video_lock);
- /* We only call ->add() here to activate and probe the camera.
- * We shall ->remove() and deactivate it immediately afterwards. */
- ret = ici->ops->add(icd);
+ ret = soc_camera_video_start(icd);
if (ret < 0)
- goto eiadd;
+ goto evidstart;
+
+ /* Try to improve our guess of a reasonable window format */
+ sd = soc_camera_to_subdev(icd);
+ if (!v4l2_subdev_call(sd, video, g_fmt, &f)) {
+ icd->user_width = f.fmt.pix.width;
+ icd->user_height = f.fmt.pix.height;
+ }
- ret = icd->ops->probe(icd);
- if (ret >= 0) {
- const struct v4l2_queryctrl *qctrl;
+ /* Do we have to sysfs_remove_link() before device_unregister()? */
+ if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
+ "control"))
+ dev_warn(&icd->dev, "Failed creating the control symlink\n");
- qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
- icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
- qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
- icd->exposure = qctrl ? qctrl->default_value :
- (unsigned short)~0;
+ ici->ops->remove(icd);
- ret = soc_camera_init_user_formats(icd);
- if (ret < 0) {
- if (icd->ops->remove)
- icd->ops->remove(icd);
- goto eiufmt;
- }
+ if (icl->power)
+ icl->power(icd->pdev, 0);
- icd->height = DEFAULT_HEIGHT;
- icd->width = DEFAULT_WIDTH;
- icd->field = V4L2_FIELD_ANY;
- }
+ mutex_unlock(&icd->video_lock);
+ return 0;
+
+evidstart:
+ mutex_unlock(&icd->video_lock);
+ soc_camera_free_user_formats(icd);
eiufmt:
+ if (icl->board_info) {
+ soc_camera_free_i2c(icd);
+ } else {
+ icl->del_device(icl);
+ module_put(control->driver->owner);
+ }
+enodrv:
+eadddev:
+ video_device_release(icd->vdev);
+evdc:
ici->ops->remove(icd);
-eiadd:
- mutex_unlock(&icd->video_lock);
- module_put(ici->ops->owner);
-emgi:
- module_put(icd->ops->owner);
-emgd:
+eadd:
+ if (icl->power)
+ icl->power(icd->pdev, 0);
+epower:
return ret;
}
@@ -904,12 +1009,28 @@ emgd:
static int soc_camera_remove(struct device *dev)
{
struct soc_camera_device *icd = to_soc_camera_dev(dev);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct video_device *vdev = icd->vdev;
- mutex_lock(&icd->video_lock);
- if (icd->ops->remove)
- icd->ops->remove(icd);
- mutex_unlock(&icd->video_lock);
+ BUG_ON(!dev->parent);
+ if (vdev) {
+ mutex_lock(&icd->video_lock);
+ video_unregister_device(vdev);
+ icd->vdev = NULL;
+ mutex_unlock(&icd->video_lock);
+ }
+
+ if (icl->board_info) {
+ soc_camera_free_i2c(icd);
+ } else {
+ struct device_driver *drv = to_soc_camera_control(icd) ?
+ to_soc_camera_control(icd)->driver : NULL;
+ if (drv) {
+ icl->del_device(icl);
+ module_put(drv->owner);
+ }
+ }
soc_camera_free_user_formats(icd);
return 0;
@@ -957,14 +1078,33 @@ static void dummy_release(struct device *dev)
{
}
+static int default_cropcap(struct soc_camera_device *icd,
+ struct v4l2_cropcap *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, cropcap, a);
+}
+
+static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, g_crop, a);
+}
+
+static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, s_crop, a);
+}
+
int soc_camera_host_register(struct soc_camera_host *ici)
{
struct soc_camera_host *ix;
+ int ret;
if (!ici || !ici->ops ||
!ici->ops->try_fmt ||
!ici->ops->set_fmt ||
- !ici->ops->set_crop ||
!ici->ops->set_bus_param ||
!ici->ops->querycap ||
!ici->ops->init_videobuf ||
@@ -972,18 +1112,27 @@ int soc_camera_host_register(struct soc_camera_host *ici)
!ici->ops->add ||
!ici->ops->remove ||
!ici->ops->poll ||
- !ici->dev)
+ !ici->v4l2_dev.dev)
return -EINVAL;
+ if (!ici->ops->set_crop)
+ ici->ops->set_crop = default_s_crop;
+ if (!ici->ops->get_crop)
+ ici->ops->get_crop = default_g_crop;
+ if (!ici->ops->cropcap)
+ ici->ops->cropcap = default_cropcap;
+
mutex_lock(&list_lock);
list_for_each_entry(ix, &hosts, list) {
if (ix->nr == ici->nr) {
- mutex_unlock(&list_lock);
- return -EBUSY;
+ ret = -EBUSY;
+ goto edevreg;
}
}
- dev_set_drvdata(ici->dev, ici);
+ ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
+ if (ret < 0)
+ goto edevreg;
list_add_tail(&ici->list, &hosts);
mutex_unlock(&list_lock);
@@ -991,6 +1140,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
scan_add_host(ici);
return 0;
+
+edevreg:
+ mutex_unlock(&list_lock);
+ return ret;
}
EXPORT_SYMBOL(soc_camera_host_register);
@@ -1004,42 +1157,34 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
list_del(&ici->list);
list_for_each_entry(icd, &devices, list) {
- if (icd->dev.parent == ici->dev) {
+ if (icd->iface == ici->nr) {
+ /* The bus->remove will be called */
device_unregister(&icd->dev);
/* Not before device_unregister(), .remove
* needs parent to call ici->ops->remove() */
icd->dev.parent = NULL;
+
+ /* If the host module is loaded again, device_register()
+ * would complain "already initialised" */
memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
}
}
mutex_unlock(&list_lock);
- dev_set_drvdata(ici->dev, NULL);
+ v4l2_device_unregister(&ici->v4l2_dev);
}
EXPORT_SYMBOL(soc_camera_host_unregister);
/* Image capture device */
-int soc_camera_device_register(struct soc_camera_device *icd)
+static int soc_camera_device_register(struct soc_camera_device *icd)
{
struct soc_camera_device *ix;
int num = -1, i;
- if (!icd || !icd->ops ||
- !icd->ops->probe ||
- !icd->ops->init ||
- !icd->ops->release ||
- !icd->ops->start_capture ||
- !icd->ops->stop_capture ||
- !icd->ops->set_crop ||
- !icd->ops->set_fmt ||
- !icd->ops->try_fmt ||
- !icd->ops->query_bus_param ||
- !icd->ops->set_bus_param)
- return -EINVAL;
-
for (i = 0; i < 256 && num < 0; i++) {
num = i;
+ /* Check if this index is available on this interface */
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
@@ -1061,21 +1206,15 @@ int soc_camera_device_register(struct soc_camera_device *icd)
icd->host_priv = NULL;
mutex_init(&icd->video_lock);
- return scan_add_device(icd);
+ list_add_tail(&icd->list, &devices);
+
+ return 0;
}
-EXPORT_SYMBOL(soc_camera_device_register);
-void soc_camera_device_unregister(struct soc_camera_device *icd)
+static void soc_camera_device_unregister(struct soc_camera_device *icd)
{
- mutex_lock(&list_lock);
list_del(&icd->list);
-
- /* The bus->remove will be eventually called */
- if (icd->dev.parent)
- device_unregister(&icd->dev);
- mutex_unlock(&list_lock);
}
-EXPORT_SYMBOL(soc_camera_device_unregister);
static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_querycap = soc_camera_querycap,
@@ -1106,23 +1245,13 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
#endif
};
-/*
- * Usually called from the struct soc_camera_ops .probe() method, i.e., from
- * soc_camera_probe() above with .video_lock held
- */
-int soc_camera_video_start(struct soc_camera_device *icd)
+static int video_dev_create(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- int err = -ENOMEM;
- struct video_device *vdev;
+ struct video_device *vdev = video_device_alloc();
- if (!icd->dev.parent)
- return -ENODEV;
-
- vdev = video_device_alloc();
if (!vdev)
- goto evidallocd;
- dev_dbg(ici->dev, "Allocated video_device %p\n", vdev);
+ return -ENOMEM;
strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
@@ -1132,87 +1261,93 @@ int soc_camera_video_start(struct soc_camera_device *icd)
vdev->ioctl_ops = &soc_camera_ioctl_ops;
vdev->release = video_device_release;
vdev->minor = -1;
- vdev->tvnorms = V4L2_STD_UNKNOWN,
+ vdev->tvnorms = V4L2_STD_UNKNOWN;
- err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
- if (err < 0) {
- dev_err(vdev->parent, "video_register_device failed\n");
- goto evidregd;
- }
icd->vdev = vdev;
return 0;
-
-evidregd:
- video_device_release(vdev);
-evidallocd:
- return err;
}
-EXPORT_SYMBOL(soc_camera_video_start);
-/* Called from client .remove() methods with .video_lock held */
-void soc_camera_video_stop(struct soc_camera_device *icd)
+/*
+ * Called from soc_camera_probe() above (with .video_lock held???)
+ */
+static int soc_camera_video_start(struct soc_camera_device *icd)
{
- struct video_device *vdev = icd->vdev;
+ int ret;
- dev_dbg(&icd->dev, "%s\n", __func__);
+ if (!icd->dev.parent)
+ return -ENODEV;
- if (!icd->dev.parent || !vdev)
- return;
+ if (!icd->ops ||
+ !icd->ops->query_bus_param ||
+ !icd->ops->set_bus_param)
+ return -EINVAL;
+
+ ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER,
+ icd->vdev->minor);
+ if (ret < 0) {
+ dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
+ return ret;
+ }
- video_unregister_device(vdev);
- icd->vdev = NULL;
+ return 0;
}
-EXPORT_SYMBOL(soc_camera_video_stop);
static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
{
struct soc_camera_link *icl = pdev->dev.platform_data;
- struct i2c_adapter *adap;
- struct i2c_client *client;
+ struct soc_camera_device *icd;
+ int ret;
if (!icl)
return -EINVAL;
- adap = i2c_get_adapter(icl->i2c_adapter_id);
- if (!adap) {
- dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n",
- icl->i2c_adapter_id);
- /* -ENODEV and -ENXIO do not produce an error on probe()... */
- return -ENOENT;
- }
-
- icl->board_info->platform_data = icl;
- client = i2c_new_device(adap, icl->board_info);
- if (!client) {
- i2c_put_adapter(adap);
+ icd = kzalloc(sizeof(*icd), GFP_KERNEL);
+ if (!icd)
return -ENOMEM;
- }
- platform_set_drvdata(pdev, client);
+ icd->iface = icl->bus_id;
+ icd->pdev = &pdev->dev;
+ platform_set_drvdata(pdev, icd);
+ icd->dev.platform_data = icl;
+
+ ret = soc_camera_device_register(icd);
+ if (ret < 0)
+ goto escdevreg;
+
+ icd->user_width = DEFAULT_WIDTH;
+ icd->user_height = DEFAULT_HEIGHT;
return 0;
+
+escdevreg:
+ kfree(icd);
+
+ return ret;
}
+/* Only called on rmmod for each platform device, since they are not
+ * hot-pluggable. Now we know, that all our users - hosts and devices have
+ * been unloaded already */
static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
{
- struct i2c_client *client = platform_get_drvdata(pdev);
+ struct soc_camera_device *icd = platform_get_drvdata(pdev);
- if (!client)
- return -ENODEV;
+ if (!icd)
+ return -EINVAL;
- i2c_unregister_device(client);
- i2c_put_adapter(client->adapter);
+ soc_camera_device_unregister(icd);
+
+ kfree(icd);
return 0;
}
static struct platform_driver __refdata soc_camera_pdrv = {
- .probe = soc_camera_pdrv_probe,
- .remove = __devexit_p(soc_camera_pdrv_remove),
- .driver = {
- .name = "soc-camera-pdrv",
- .owner = THIS_MODULE,
+ .remove = __devexit_p(soc_camera_pdrv_remove),
+ .driver = {
+ .name = "soc-camera-pdrv",
+ .owner = THIS_MODULE,
},
};
@@ -1225,7 +1360,7 @@ static int __init soc_camera_init(void)
if (ret)
goto edrvr;
- ret = platform_driver_register(&soc_camera_pdrv);
+ ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
if (ret)
goto epdr;
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index c48676356ab7..b6a575ce5da2 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -16,54 +16,32 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
struct soc_camera_platform_priv {
- struct soc_camera_platform_info *info;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
struct soc_camera_data_format format;
};
-static struct soc_camera_platform_info *
-soc_camera_platform_get_info(struct soc_camera_device *icd)
+static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev)
{
- struct soc_camera_platform_priv *priv;
- priv = container_of(icd, struct soc_camera_platform_priv, icd);
- return priv->info;
-}
-
-static int soc_camera_platform_init(struct soc_camera_device *icd)
-{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
-
- if (p->power)
- p->power(1);
-
- return 0;
-}
-
-static int soc_camera_platform_release(struct soc_camera_device *icd)
-{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
-
- if (p->power)
- p->power(0);
-
- return 0;
+ struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+ return container_of(subdev, struct soc_camera_platform_priv, subdev);
}
-static int soc_camera_platform_start_capture(struct soc_camera_device *icd)
+static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd)
{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
- return p->set_capture(p, 1);
+ struct platform_device *pdev =
+ to_platform_device(to_soc_camera_control(icd));
+ return pdev->dev.platform_data;
}
-static int soc_camera_platform_stop_capture(struct soc_camera_device *icd)
+static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
- return p->set_capture(p, 0);
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+ return p->set_capture(p, enable);
}
static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd,
@@ -75,26 +53,14 @@ static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd,
static unsigned long
soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+ struct soc_camera_platform_info *p = get_info(icd);
return p->bus_param;
}
-static int soc_camera_platform_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
-{
- return 0;
-}
-
-static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
+static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
struct v4l2_format *f)
{
- return 0;
-}
-
-static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
struct v4l2_pix_format *pix = &f->fmt.pix;
pix->width = p->format.width;
@@ -102,82 +68,99 @@ static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int soc_camera_platform_video_probe(struct soc_camera_device *icd)
+static void soc_camera_platform_video_probe(struct soc_camera_device *icd,
+ struct platform_device *pdev)
{
- struct soc_camera_platform_priv *priv;
- priv = container_of(icd, struct soc_camera_platform_priv, icd);
+ struct soc_camera_platform_priv *priv = get_priv(pdev);
+ struct soc_camera_platform_info *p = pdev->dev.platform_data;
- priv->format.name = priv->info->format_name;
- priv->format.depth = priv->info->format_depth;
- priv->format.fourcc = priv->info->format.pixelformat;
- priv->format.colorspace = priv->info->format.colorspace;
+ priv->format.name = p->format_name;
+ priv->format.depth = p->format_depth;
+ priv->format.fourcc = p->format.pixelformat;
+ priv->format.colorspace = p->format.colorspace;
icd->formats = &priv->format;
icd->num_formats = 1;
-
- return soc_camera_video_start(icd);
}
-static void soc_camera_platform_video_remove(struct soc_camera_device *icd)
-{
- soc_camera_video_stop(icd);
-}
+static struct v4l2_subdev_core_ops platform_subdev_core_ops;
+
+static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
+ .s_stream = soc_camera_platform_s_stream,
+ .try_fmt = soc_camera_platform_try_fmt,
+};
+
+static struct v4l2_subdev_ops platform_subdev_ops = {
+ .core = &platform_subdev_core_ops,
+ .video = &platform_subdev_video_ops,
+};
static struct soc_camera_ops soc_camera_platform_ops = {
- .owner = THIS_MODULE,
- .probe = soc_camera_platform_video_probe,
- .remove = soc_camera_platform_video_remove,
- .init = soc_camera_platform_init,
- .release = soc_camera_platform_release,
- .start_capture = soc_camera_platform_start_capture,
- .stop_capture = soc_camera_platform_stop_capture,
- .set_crop = soc_camera_platform_set_crop,
- .set_fmt = soc_camera_platform_set_fmt,
- .try_fmt = soc_camera_platform_try_fmt,
.set_bus_param = soc_camera_platform_set_bus_param,
.query_bus_param = soc_camera_platform_query_bus_param,
};
static int soc_camera_platform_probe(struct platform_device *pdev)
{
+ struct soc_camera_host *ici;
struct soc_camera_platform_priv *priv;
- struct soc_camera_platform_info *p;
+ struct soc_camera_platform_info *p = pdev->dev.platform_data;
struct soc_camera_device *icd;
int ret;
- p = pdev->dev.platform_data;
if (!p)
return -EINVAL;
+ if (!p->dev) {
+ dev_err(&pdev->dev,
+ "Platform has not set soc_camera_device pointer!\n");
+ return -EINVAL;
+ }
+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->info = p;
- platform_set_drvdata(pdev, priv);
+ icd = to_soc_camera_dev(p->dev);
+
+ /* soc-camera convention: control's drvdata points to the subdev */
+ platform_set_drvdata(pdev, &priv->subdev);
+ /* Set the control device reference */
+ dev_set_drvdata(&icd->dev, &pdev->dev);
+
+ icd->y_skip_top = 0;
+ icd->ops = &soc_camera_platform_ops;
+
+ ici = to_soc_camera_host(icd->dev.parent);
- icd = &priv->icd;
- icd->ops = &soc_camera_platform_ops;
- icd->control = &pdev->dev;
- icd->width_min = 0;
- icd->width_max = priv->info->format.width;
- icd->height_min = 0;
- icd->height_max = priv->info->format.height;
- icd->y_skip_top = 0;
- icd->iface = priv->info->iface;
+ soc_camera_platform_video_probe(icd, pdev);
- ret = soc_camera_device_register(icd);
+ v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
+ v4l2_set_subdevdata(&priv->subdev, p);
+ strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
+
+ ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
if (ret)
- kfree(priv);
+ goto evdrs;
+
+ return ret;
+evdrs:
+ icd->ops = NULL;
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
return ret;
}
static int soc_camera_platform_remove(struct platform_device *pdev)
{
- struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+ struct soc_camera_platform_priv *priv = get_priv(pdev);
+ struct soc_camera_platform_info *p = pdev->dev.platform_data;
+ struct soc_camera_device *icd = to_soc_camera_dev(p->dev);
- soc_camera_device_unregister(&priv->icd);
+ v4l2_device_unregister_subdev(&priv->subdev);
+ icd->ops = NULL;
+ platform_set_drvdata(pdev, NULL);
kfree(priv);
return 0;
}
@@ -185,6 +168,7 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
static struct platform_driver soc_camera_platform_driver = {
.driver = {
.name = "soc_camera_platform",
+ .owner = THIS_MODULE,
},
.probe = soc_camera_platform_probe,
.remove = soc_camera_platform_remove,
@@ -206,3 +190,4 @@ module_exit(soc_camera_platform_module_exit);
MODULE_DESCRIPTION("SoC Camera Platform driver");
MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:soc_camera_platform");
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index b154bd961e3b..0b996ea4134e 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -1400,7 +1400,6 @@ static int stk_camera_probe(struct usb_interface *interface,
}
stk_create_sysfs_files(&dev->vdev);
- usb_autopm_enable(dev->interface);
return 0;
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 8b4e7dafce7b..6a91714125d2 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -734,10 +734,6 @@ static int stv680_start_stream (struct usb_stv *stv680)
return 0;
nomem_err:
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- kfree(stv680->scratch[i].data);
- stv680->scratch[i].data = NULL;
- }
for (i = 0; i < STV680_NUMSBUF; i++) {
usb_kill_urb(stv680->urb[i]);
usb_free_urb(stv680->urb[i]);
@@ -745,6 +741,11 @@ static int stv680_start_stream (struct usb_stv *stv680)
kfree(stv680->sbuf[i].data);
stv680->sbuf[i].data = NULL;
}
+ /* used in irq, free only as all URBs are dead */
+ for (i = 0; i < STV680_NUMSCRATCH; i++) {
+ kfree(stv680->scratch[i].data);
+ stv680->scratch[i].data = NULL;
+ }
return -ENOMEM;
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 537594211a90..2816f1839230 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -819,8 +819,8 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
- (abs_freq * 2 + 125/2) / 125 :
- (abs_freq + 62500/2) / 62500;
+ DIV_ROUND_CLOSEST(abs_freq * 2, 125) :
+ DIV_ROUND_CLOSEST(abs_freq, 62500);
return 0;
}
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index ac02808106c1..d533ea57e7b1 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -646,14 +646,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->has_radio = 1;
}
- if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
+ if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) {
tvee->tuner_type = hauppauge_tuner[tuner1].id;
t_name1 = hauppauge_tuner[tuner1].name;
} else {
t_name1 = "unknown";
}
- if (tuner2 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
+ if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) {
tvee->tuner2_type = hauppauge_tuner[tuner2].id;
t_name2 = hauppauge_tuner[tuner2].name;
} else {
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index 3750f7fadb12..244372627df2 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -31,7 +31,10 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
-#include <media/v4l2-int-device.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
#include <media/tvp514x.h>
#include "tvp514x_regs.h"
@@ -49,15 +52,11 @@ static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dump_reg(client, reg, val) \
- do { \
- val = tvp514x_read_reg(client, reg); \
- v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
- } while (0)
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TVP514X linux decoder driver");
+MODULE_LICENSE("GPL");
-/**
- * enum tvp514x_std - enum for supported standards
- */
+/* enum tvp514x_std - enum for supported standards */
enum tvp514x_std {
STD_NTSC_MJ = 0,
STD_PAL_BDGHIN,
@@ -65,14 +64,6 @@ enum tvp514x_std {
};
/**
- * enum tvp514x_state - enum for different decoder states
- */
-enum tvp514x_state {
- STATE_NOT_DETECTED,
- STATE_DETECTED
-};
-
-/**
* struct tvp514x_std_info - Structure to store standard informations
* @width: Line width in pixels
* @height:Number of active lines
@@ -89,33 +80,27 @@ struct tvp514x_std_info {
static struct tvp514x_reg tvp514x_reg_list_default[0x40];
/**
* struct tvp514x_decoder - TVP5146/47 decoder object
- * @v4l2_int_device: Slave handle
- * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device
+ * @sd: Subdevice Slave handle
* @tvp514x_regs: copy of hw's regs with preset values.
* @pdata: Board specific
- * @client: I2C client data
- * @id: Entry from I2C table
* @ver: Chip version
- * @state: TVP5146/47 decoder state - detected or not-detected
+ * @streaming: TVP5146/47 decoder streaming - enabled or disabled.
* @pix: Current pixel format
* @num_fmts: Number of formats
* @fmt_list: Format list
* @current_std: Current standard
* @num_stds: Number of standards
* @std_list: Standards list
- * @route: input and output routing at chip level
+ * @input: Input routing at chip level
+ * @output: Output routing at chip level
*/
struct tvp514x_decoder {
- struct v4l2_int_device v4l2_int_device;
- struct v4l2_int_slave tvp514x_slave;
+ struct v4l2_subdev sd;
struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
const struct tvp514x_platform_data *pdata;
- struct i2c_client *client;
-
- struct i2c_device_id *id;
int ver;
- enum tvp514x_state state;
+ int streaming;
struct v4l2_pix_format pix;
int num_fmts;
@@ -124,15 +109,18 @@ struct tvp514x_decoder {
enum tvp514x_std current_std;
int num_stds;
struct tvp514x_std_info *std_list;
-
- struct v4l2_routing route;
+ /* Input and Output Routing parameters */
+ u32 input;
+ u32 output;
};
/* TVP514x default register values */
static struct tvp514x_reg tvp514x_reg_list_default[] = {
- {TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */
+ /* Composite selected */
+ {TOK_WRITE, REG_INPUT_SEL, 0x05},
{TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
- {TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */
+ /* Auto mode */
+ {TOK_WRITE, REG_VIDEO_STD, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
{TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
{TOK_WRITE, REG_COLOR_KILLER, 0x10},
@@ -145,53 +133,74 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = {
{TOK_WRITE, REG_HUE, 0x00},
{TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
{TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
- {TOK_SKIP, 0x0F, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x0F, 0x00},
{TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
{TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
{TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
- {TOK_SKIP, 0x13, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x13, 0x00},
{TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
- {TOK_SKIP, 0x15, 0x00}, /* Reserved */
- {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, /* NTSC timing */
+ /* Reserved */
+ {TOK_SKIP, 0x15, 0x00},
+ /* NTSC timing */
+ {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55},
{TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00},
{TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25},
{TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03},
- {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, /* NTSC timing */
+ /* NTSC timing */
+ {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00},
{TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00},
{TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
{TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
- {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, /* NTSC timing */
+ /* NTSC timing */
+ {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04},
{TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
{TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
{TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
- {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, /* NTSC timing */
+ /* NTSC timing */
+ {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01},
{TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
{TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
{TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
- {TOK_SKIP, 0x26, 0x00}, /* Reserved */
- {TOK_SKIP, 0x27, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x26, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x27, 0x00},
{TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
- {TOK_SKIP, 0x29, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x29, 0x00},
{TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
- {TOK_SKIP, 0x2B, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x2B, 0x00},
{TOK_SKIP, REG_SCART_DELAY, 0x00},
{TOK_SKIP, REG_CTI_DELAY, 0x00},
{TOK_SKIP, REG_CTI_CONTROL, 0x00},
- {TOK_SKIP, 0x2F, 0x00}, /* Reserved */
- {TOK_SKIP, 0x30, 0x00}, /* Reserved */
- {TOK_SKIP, 0x31, 0x00}, /* Reserved */
- {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, /* HS, VS active high */
- {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, /* 10-bit BT.656 */
- {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, /* Enable clk & data */
- {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, /* Enable AVID & FLD */
- {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, /* Enable VS & HS */
+ /* Reserved */
+ {TOK_SKIP, 0x2F, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x30, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x31, 0x00},
+ /* HS, VS active high */
+ {TOK_WRITE, REG_SYNC_CONTROL, 0x00},
+ /* 10-bit BT.656 */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00},
+ /* Enable clk & data */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11},
+ /* Enable AVID & FLD */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE},
+ /* Enable VS & HS */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF},
{TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
{TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
- {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, /* Clear status */
+ /* Clear status */
+ {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01},
{TOK_TERM, 0, 0},
};
-/* List of image formats supported by TVP5146/47 decoder
+/**
+ * List of image formats supported by TVP5146/47 decoder
* Currently we are using 8 bit mode only, but can be
* extended to 10/20 bit mode.
*/
@@ -205,7 +214,7 @@ static const struct v4l2_fmtdesc tvp514x_fmt_list[] = {
},
};
-/*
+/**
* Supported standards -
*
* Currently supports two standards only, need to add support for rest of the
@@ -240,35 +249,32 @@ static struct tvp514x_std_info tvp514x_std_list[] = {
},
/* Standard: need to add for additional standard */
};
-/*
- * Control structure for Auto Gain
- * This is temporary data, will get replaced once
- * v4l2_ctrl_query_fill supports it.
- */
-static const struct v4l2_queryctrl tvp514x_autogain_ctrl = {
- .id = V4L2_CID_AUTOGAIN,
- .name = "Gain, Automatic",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
-};
-/*
- * Read a value from a register in an TVP5146/47 decoder device.
+
+static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tvp514x_decoder, sd);
+}
+
+
+/**
+ * tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ *
* Returns value read if successful, or non-zero (-1) otherwise.
*/
-static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
+static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
{
- int err;
- int retry = 0;
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
read_again:
err = i2c_smbus_read_byte_data(client, reg);
if (err == -1) {
if (retry <= I2C_RETRY_COUNT) {
- v4l_warn(client, "Read: retry ... %d\n", retry);
+ v4l2_warn(sd, "Read: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto read_again;
@@ -278,20 +284,39 @@ read_again:
return err;
}
-/*
+/**
+ * dump_reg() - dump the register content of TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ */
+static void dump_reg(struct v4l2_subdev *sd, u8 reg)
+{
+ u32 val;
+
+ val = tvp514x_read_reg(sd, reg);
+ v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
+}
+
+/**
+ * tvp514x_write_reg() - Write a value to a register in TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ * @val: value to be written to the register
+ *
* Write a value to a register in an TVP5146/47 decoder device.
* Returns zero if successful, or non-zero otherwise.
*/
-static int tvp514x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- int err;
- int retry = 0;
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
write_again:
err = i2c_smbus_write_byte_data(client, reg, val);
if (err) {
if (retry <= I2C_RETRY_COUNT) {
- v4l_warn(client, "Write: retry ... %d\n", retry);
+ v4l2_warn(sd, "Write: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto write_again;
@@ -301,17 +326,19 @@ write_again:
return err;
}
-/*
- * tvp514x_write_regs : Initializes a list of TVP5146/47 registers
+/**
+ * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @reglist: list of TVP5146/47 registers and values
+ *
+ * Initializes a list of TVP5146/47 registers:-
* if token is TOK_TERM, then entire write operation terminates
* if token is TOK_DELAY, then a delay of 'val' msec is introduced
* if token is TOK_SKIP, then the register write is skipped
* if token is TOK_WRITE, then the register write is performed
- *
- * reglist - list of registers to be written
* Returns zero if successful, or non-zero otherwise.
*/
-static int tvp514x_write_regs(struct i2c_client *client,
+static int tvp514x_write_regs(struct v4l2_subdev *sd,
const struct tvp514x_reg reglist[])
{
int err;
@@ -326,31 +353,33 @@ static int tvp514x_write_regs(struct i2c_client *client,
if (next->token == TOK_SKIP)
continue;
- err = tvp514x_write_reg(client, next->reg, (u8) next->val);
+ err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
if (err) {
- v4l_err(client, "Write failed. Err[%d]\n", err);
+ v4l2_err(sd, "Write failed. Err[%d]\n", err);
return err;
}
}
return 0;
}
-/*
- * tvp514x_get_current_std:
- * Returns the current standard detected by TVP5146/47
+/**
+ * tvp514x_get_current_std() : Get the current standard detected by TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Get current standard detected by TVP5146/47, STD_INVALID if there is no
+ * standard detected.
*/
-static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
- *decoder)
+static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd)
{
u8 std, std_status;
- std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
- if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
+ std = tvp514x_read_reg(sd, REG_VIDEO_STD);
+ if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT)
/* use the standard status register */
- std_status = tvp514x_read_reg(decoder->client,
- REG_VIDEO_STD_STATUS);
- } else
- std_status = std; /* use the standard register itself */
+ std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
+ else
+ /* use the standard register itself */
+ std_status = std;
switch (std_status & VIDEO_STD_MASK) {
case VIDEO_STD_NTSC_MJ_BIT:
@@ -366,94 +395,99 @@ static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
return STD_INVALID;
}
-/*
- * TVP5146/47 register dump function
- */
-static void tvp514x_reg_dump(struct tvp514x_decoder *decoder)
+/* TVP5146/47 register dump function */
+static void tvp514x_reg_dump(struct v4l2_subdev *sd)
{
- u8 value;
-
- dump_reg(decoder->client, REG_INPUT_SEL, value);
- dump_reg(decoder->client, REG_AFE_GAIN_CTRL, value);
- dump_reg(decoder->client, REG_VIDEO_STD, value);
- dump_reg(decoder->client, REG_OPERATION_MODE, value);
- dump_reg(decoder->client, REG_COLOR_KILLER, value);
- dump_reg(decoder->client, REG_LUMA_CONTROL1, value);
- dump_reg(decoder->client, REG_LUMA_CONTROL2, value);
- dump_reg(decoder->client, REG_LUMA_CONTROL3, value);
- dump_reg(decoder->client, REG_BRIGHTNESS, value);
- dump_reg(decoder->client, REG_CONTRAST, value);
- dump_reg(decoder->client, REG_SATURATION, value);
- dump_reg(decoder->client, REG_HUE, value);
- dump_reg(decoder->client, REG_CHROMA_CONTROL1, value);
- dump_reg(decoder->client, REG_CHROMA_CONTROL2, value);
- dump_reg(decoder->client, REG_COMP_PR_SATURATION, value);
- dump_reg(decoder->client, REG_COMP_Y_CONTRAST, value);
- dump_reg(decoder->client, REG_COMP_PB_SATURATION, value);
- dump_reg(decoder->client, REG_COMP_Y_BRIGHTNESS, value);
- dump_reg(decoder->client, REG_AVID_START_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_AVID_START_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_AVID_STOP_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_AVID_STOP_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_HSYNC_START_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_HSYNC_START_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_VSYNC_START_LINE_LSB, value);
- dump_reg(decoder->client, REG_VSYNC_START_LINE_MSB, value);
- dump_reg(decoder->client, REG_VSYNC_STOP_LINE_LSB, value);
- dump_reg(decoder->client, REG_VSYNC_STOP_LINE_MSB, value);
- dump_reg(decoder->client, REG_VBLK_START_LINE_LSB, value);
- dump_reg(decoder->client, REG_VBLK_START_LINE_MSB, value);
- dump_reg(decoder->client, REG_VBLK_STOP_LINE_LSB, value);
- dump_reg(decoder->client, REG_VBLK_STOP_LINE_MSB, value);
- dump_reg(decoder->client, REG_SYNC_CONTROL, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER1, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER2, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER3, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER4, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER5, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER6, value);
- dump_reg(decoder->client, REG_CLEAR_LOST_LOCK, value);
+ dump_reg(sd, REG_INPUT_SEL);
+ dump_reg(sd, REG_AFE_GAIN_CTRL);
+ dump_reg(sd, REG_VIDEO_STD);
+ dump_reg(sd, REG_OPERATION_MODE);
+ dump_reg(sd, REG_COLOR_KILLER);
+ dump_reg(sd, REG_LUMA_CONTROL1);
+ dump_reg(sd, REG_LUMA_CONTROL2);
+ dump_reg(sd, REG_LUMA_CONTROL3);
+ dump_reg(sd, REG_BRIGHTNESS);
+ dump_reg(sd, REG_CONTRAST);
+ dump_reg(sd, REG_SATURATION);
+ dump_reg(sd, REG_HUE);
+ dump_reg(sd, REG_CHROMA_CONTROL1);
+ dump_reg(sd, REG_CHROMA_CONTROL2);
+ dump_reg(sd, REG_COMP_PR_SATURATION);
+ dump_reg(sd, REG_COMP_Y_CONTRAST);
+ dump_reg(sd, REG_COMP_PB_SATURATION);
+ dump_reg(sd, REG_COMP_Y_BRIGHTNESS);
+ dump_reg(sd, REG_AVID_START_PIXEL_LSB);
+ dump_reg(sd, REG_AVID_START_PIXEL_MSB);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_LSB);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_MSB);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_LSB);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_MSB);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB);
+ dump_reg(sd, REG_VSYNC_START_LINE_LSB);
+ dump_reg(sd, REG_VSYNC_START_LINE_MSB);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_LSB);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_MSB);
+ dump_reg(sd, REG_VBLK_START_LINE_LSB);
+ dump_reg(sd, REG_VBLK_START_LINE_MSB);
+ dump_reg(sd, REG_VBLK_STOP_LINE_LSB);
+ dump_reg(sd, REG_VBLK_STOP_LINE_MSB);
+ dump_reg(sd, REG_SYNC_CONTROL);
+ dump_reg(sd, REG_OUTPUT_FORMATTER1);
+ dump_reg(sd, REG_OUTPUT_FORMATTER2);
+ dump_reg(sd, REG_OUTPUT_FORMATTER3);
+ dump_reg(sd, REG_OUTPUT_FORMATTER4);
+ dump_reg(sd, REG_OUTPUT_FORMATTER5);
+ dump_reg(sd, REG_OUTPUT_FORMATTER6);
+ dump_reg(sd, REG_CLEAR_LOST_LOCK);
}
-/*
- * Configure the TVP5146/47 with the current register settings
+/**
+ * tvp514x_configure() - Configure the TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @decoder: ptr to tvp514x_decoder structure
+ *
* Returns zero if successful, or non-zero otherwise.
*/
-static int tvp514x_configure(struct tvp514x_decoder *decoder)
+static int tvp514x_configure(struct v4l2_subdev *sd,
+ struct tvp514x_decoder *decoder)
{
int err;
/* common register initialization */
err =
- tvp514x_write_regs(decoder->client, decoder->tvp514x_regs);
+ tvp514x_write_regs(sd, decoder->tvp514x_regs);
if (err)
return err;
if (debug)
- tvp514x_reg_dump(decoder);
+ tvp514x_reg_dump(sd);
return 0;
}
-/*
- * Detect if an tvp514x is present, and if so which revision.
+/**
+ * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision.
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @decoder: pointer to tvp514x_decoder structure
+ *
* A device is considered to be detected if the chip ID (LSB and MSB)
* registers match the expected values.
* Any value of the rom version register is accepted.
* Returns ENODEV error number if no device is detected, or zero
* if a device is detected.
*/
-static int tvp514x_detect(struct tvp514x_decoder *decoder)
+static int tvp514x_detect(struct v4l2_subdev *sd,
+ struct tvp514x_decoder *decoder)
{
u8 chip_id_msb, chip_id_lsb, rom_ver;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- chip_id_msb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_MSB);
- chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
- rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
+ chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB);
+ chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB);
+ rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION);
- v4l_dbg(1, debug, decoder->client,
+ v4l2_dbg(1, debug, sd,
"chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
chip_id_msb, chip_id_lsb, rom_ver);
if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
@@ -462,38 +496,30 @@ static int tvp514x_detect(struct tvp514x_decoder *decoder)
/* We didn't read the values we expected, so this must not be
* an TVP5146/47.
*/
- v4l_err(decoder->client,
- "chip id mismatch msb:0x%x lsb:0x%x\n",
- chip_id_msb, chip_id_lsb);
+ v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n",
+ chip_id_msb, chip_id_lsb);
return -ENODEV;
}
decoder->ver = rom_ver;
- decoder->state = STATE_DETECTED;
- v4l_info(decoder->client,
- "%s found at 0x%x (%s)\n", decoder->client->name,
- decoder->client->addr << 1,
- decoder->client->adapter->name);
+ v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n",
+ client->name, decoder->ver,
+ client->addr << 1, client->adapter->name);
return 0;
}
-/*
- * Following are decoder interface functions implemented by
- * TVP5146/47 decoder driver.
- */
-
/**
- * ioctl_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_querystd() - V4L2 decoder interface handler for querystd
+ * @sd: pointer to standard V4L2 sub-device structure
* @std_id: standard V4L2 std_id ioctl enum
*
* Returns the current standard detected by TVP5146/47. If no active input is
* detected, returns -EINVAL
*/
-static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
+static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
enum tvp514x_std current_std;
enum tvp514x_input input_sel;
u8 sync_lock_status, lock_mask;
@@ -502,11 +528,11 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
return -EINVAL;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
- input_sel = decoder->route.input;
+ input_sel = decoder->input;
switch (input_sel) {
case INPUT_CVBS_VI1A:
@@ -544,42 +570,39 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
return -EINVAL;
}
/* check whether signal is locked */
- sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
+ sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
if (lock_mask != (sync_lock_status & lock_mask))
return -EINVAL; /* No input detected */
decoder->current_std = current_std;
*std_id = decoder->std_list[current_std].standard.id;
- v4l_dbg(1, debug, decoder->client, "Current STD: %s",
+ v4l2_dbg(1, debug, sd, "Current STD: %s",
decoder->std_list[current_std].standard.name);
return 0;
}
/**
- * ioctl_s_std - V4L2 decoder interface handler for VIDIOC_S_STD ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_std() - V4L2 decoder interface handler for s_std
+ * @sd: pointer to standard V4L2 sub-device structure
* @std_id: standard V4L2 v4l2_std_id ioctl enum
*
* If std_id is supported, sets the requested standard. Otherwise, returns
* -EINVAL
*/
-static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
+static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err, i;
- if (std_id == NULL)
- return -EINVAL;
-
for (i = 0; i < decoder->num_stds; i++)
- if (*std_id & decoder->std_list[i].standard.id)
+ if (std_id & decoder->std_list[i].standard.id)
break;
if ((i == decoder->num_stds) || (i == STD_INVALID))
return -EINVAL;
- err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD,
+ err = tvp514x_write_reg(sd, REG_VIDEO_STD,
decoder->std_list[i].video_std);
if (err)
return err;
@@ -588,24 +611,26 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
decoder->tvp514x_regs[REG_VIDEO_STD].val =
decoder->std_list[i].video_std;
- v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
+ v4l2_dbg(1, debug, sd, "Standard set to: %s",
decoder->std_list[i].standard.name);
return 0;
}
/**
- * ioctl_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
- * @s: pointer to standard V4L2 device structure
- * @index: number of the input
+ * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @input: input selector for routing the signal
+ * @output: output selector for routing the signal
+ * @config: config value. Not used
*
* If index is valid, selects the requested input. Otherwise, returns -EINVAL if
* the input is not supported or there is no active signal present in the
* selected input.
*/
-static int ioctl_s_routing(struct v4l2_int_device *s,
- struct v4l2_routing *route)
+static int tvp514x_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err;
enum tvp514x_input input_sel;
enum tvp514x_output output_sel;
@@ -613,20 +638,21 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
u8 sync_lock_status, lock_mask;
int try_count = LOCK_RETRY_COUNT;
- if ((!route) || (route->input >= INPUT_INVALID) ||
- (route->output >= OUTPUT_INVALID))
- return -EINVAL; /* Index out of bound */
+ if ((input >= INPUT_INVALID) ||
+ (output >= OUTPUT_INVALID))
+ /* Index out of bound */
+ return -EINVAL;
- input_sel = route->input;
- output_sel = route->output;
+ input_sel = input;
+ output_sel = output;
- err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel);
+ err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
if (err)
return err;
- output_sel |= tvp514x_read_reg(decoder->client,
+ output_sel |= tvp514x_read_reg(sd,
REG_OUTPUT_FORMATTER1) & 0x7;
- err = tvp514x_write_reg(decoder->client, REG_OUTPUT_FORMATTER1,
+ err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
output_sel);
if (err)
return err;
@@ -637,7 +663,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
/* Clear status */
msleep(LOCK_RETRY_DELAY);
err =
- tvp514x_write_reg(decoder->client, REG_CLEAR_LOST_LOCK, 0x01);
+ tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
if (err)
return err;
@@ -672,7 +698,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT;
break;
- /*Need to add other interfaces*/
+ /* Need to add other interfaces*/
default:
return -EINVAL;
}
@@ -682,42 +708,41 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
msleep(LOCK_RETRY_DELAY);
/* get the current standard for future reference */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
continue;
- sync_lock_status = tvp514x_read_reg(decoder->client,
+ sync_lock_status = tvp514x_read_reg(sd,
REG_STATUS1);
if (lock_mask == (sync_lock_status & lock_mask))
- break; /* Input detected */
+ /* Input detected */
+ break;
}
if ((current_std == STD_INVALID) || (try_count < 0))
return -EINVAL;
decoder->current_std = current_std;
- decoder->route.input = route->input;
- decoder->route.output = route->output;
+ decoder->input = input;
+ decoder->output = output;
- v4l_dbg(1, debug, decoder->client,
- "Input set to: %d, std : %d",
+ v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d",
input_sel, current_std);
return 0;
}
/**
- * ioctl_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl
+ * @sd: pointer to standard V4L2 sub-device structure
* @qctrl: standard V4L2 v4l2_queryctrl structure
*
* If the requested control is supported, returns the control information.
* Otherwise, returns -EINVAL if the control is not supported.
*/
static int
-ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
+tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
int err = -EINVAL;
if (qctrl == NULL)
@@ -725,13 +750,13 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
switch (qctrl->id) {
case V4L2_CID_BRIGHTNESS:
- /* Brightness supported is (0-255),
- */
+ /* Brightness supported is (0-255), */
err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
break;
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
- /* Saturation and Contrast supported is -
+ /**
+ * Saturation and Contrast supported is -
* Contrast: 0 - 255 (Default - 128)
* Saturation: 0 - 255 (Default - 128)
*/
@@ -744,30 +769,27 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
break;
case V4L2_CID_AUTOGAIN:
- /* Autogain is either 0 or 1*/
- memcpy(qctrl, &tvp514x_autogain_ctrl,
- sizeof(struct v4l2_queryctrl));
- err = 0;
+ /**
+ * Auto Gain supported is -
+ * 0 - 1 (Default - 1)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", qctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", qctrl->id);
return err;
}
- v4l_dbg(1, debug, decoder->client,
- "Query Control: %s : Min - %d, Max - %d, Def - %d",
- qctrl->name,
- qctrl->minimum,
- qctrl->maximum,
+ v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d",
+ qctrl->name, qctrl->minimum, qctrl->maximum,
qctrl->default_value);
return err;
}
/**
- * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl
+ * @sd: pointer to standard V4L2 sub-device structure
* @ctrl: pointer to v4l2_control structure
*
* If the requested control is supported, returns the control's current
@@ -775,9 +797,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
* supported.
*/
static int
-ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
if (ctrl == NULL)
return -EINVAL;
@@ -811,74 +833,70 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", ctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return -EINVAL;
}
- v4l_dbg(1, debug, decoder->client,
- "Get Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d",
ctrl->id, ctrl->value);
return 0;
}
/**
- * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
+ * @sd: pointer to standard V4L2 sub-device structure
* @ctrl: pointer to v4l2_control structure
*
* If the requested control is supported, sets the control's current
* value in HW. Otherwise, returns -EINVAL if the control is not supported.
*/
static int
-ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err = -EINVAL, value;
if (ctrl == NULL)
return err;
- value = (__s32) ctrl->value;
+ value = ctrl->value;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(decoder->client,
- "invalid brightness setting %d\n",
+ v4l2_err(sd, "invalid brightness setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_BRIGHTNESS,
+ err = tvp514x_write_reg(sd, REG_BRIGHTNESS,
value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
break;
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(decoder->client,
- "invalid contrast setting %d\n",
+ v4l2_err(sd, "invalid contrast setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_CONTRAST,
- value);
+ err = tvp514x_write_reg(sd, REG_CONTRAST, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_CONTRAST].val = value;
break;
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(decoder->client,
- "invalid saturation setting %d\n",
+ v4l2_err(sd, "invalid saturation setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_SATURATION,
- value);
+ err = tvp514x_write_reg(sd, REG_SATURATION, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_SATURATION].val = value;
break;
case V4L2_CID_HUE:
@@ -889,15 +907,13 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
else if (value == 0)
value = 0;
else {
- v4l_err(decoder->client,
- "invalid hue setting %d\n",
- ctrl->value);
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_HUE,
- value);
+ err = tvp514x_write_reg(sd, REG_HUE, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_HUE].val = value;
break;
case V4L2_CID_AUTOGAIN:
@@ -906,41 +922,38 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
else if (value == 0)
value = 0x0C;
else {
- v4l_err(decoder->client,
- "invalid auto gain setting %d\n",
+ v4l2_err(sd, "invalid auto gain setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_AFE_GAIN_CTRL,
- value);
+ err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", ctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return err;
}
- v4l_dbg(1, debug, decoder->client,
- "Set Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d",
ctrl->id, ctrl->value);
return err;
}
/**
- * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_enum_fmt_cap() - V4L2 decoder interface handler for enum_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
* @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
*
* Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats
*/
static int
-ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
+tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int index;
if (fmt == NULL)
@@ -948,24 +961,25 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
index = fmt->index;
if ((index >= decoder->num_fmts) || (index < 0))
- return -EINVAL; /* Index out of bound */
+ /* Index out of bound */
+ return -EINVAL;
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
memcpy(fmt, &decoder->fmt_list[index],
sizeof(struct v4l2_fmtdesc));
- v4l_dbg(1, debug, decoder->client,
- "Current FMT: index - %d (%s)",
+ v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)",
decoder->fmt_list[index].index,
decoder->fmt_list[index].description);
return 0;
}
/**
- * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
*
* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
@@ -973,9 +987,9 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
* without actually making it take effect.
*/
static int
-ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int ifmt;
struct v4l2_pix_format *pix;
enum tvp514x_std current_std;
@@ -984,12 +998,13 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ /* only capture is supported */
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pix = &f->fmt.pix;
/* Calculate height and width based on current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1003,7 +1018,8 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
break;
}
if (ifmt == decoder->num_fmts)
- ifmt = 0; /* None of the format matched, select default */
+ /* None of the format matched, select default */
+ ifmt = 0;
pix->pixelformat = decoder->fmt_list[ifmt].pixelformat;
pix->field = V4L2_FIELD_INTERLACED;
@@ -1012,8 +1028,7 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
pix->priv = 0;
- v4l_dbg(1, debug, decoder->client,
- "Try FMT: pixelformat - %s, bytesperline - %d"
+ v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
"Width - %d, Height - %d",
decoder->fmt_list[ifmt].description, pix->bytesperline,
pix->width, pix->height);
@@ -1021,8 +1036,8 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
}
/**
- * ioctl_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_fmt_cap() - V4L2 decoder interface handler for s_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
*
* If the requested format is supported, configures the HW to use that
@@ -1030,9 +1045,9 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
* correctly configured.
*/
static int
-ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_pix_format *pix;
int rval;
@@ -1040,10 +1055,11 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
pix = &f->fmt.pix;
- rval = ioctl_try_fmt_cap(s, f);
+ rval = tvp514x_try_fmt_cap(sd, f);
if (rval)
return rval;
@@ -1053,28 +1069,28 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
}
/**
- * ioctl_g_fmt_cap - V4L2 decoder interface handler for ioctl_g_fmt_cap
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_g_fmt_cap() - V4L2 decoder interface handler for tvp514x_g_fmt_cap
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 v4l2_format structure
*
* Returns the decoder's current pixel format in the v4l2_format
* parameter.
*/
static int
-ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
if (f == NULL)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
f->fmt.pix = decoder->pix;
- v4l_dbg(1, debug, decoder->client,
- "Current FMT: bytesperline - %d"
+ v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
"Width - %d, Height - %d",
decoder->pix.bytesperline,
decoder->pix.width, decoder->pix.height);
@@ -1082,16 +1098,16 @@ ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
}
/**
- * ioctl_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm
+ * @sd: pointer to standard V4L2 sub-device structure
* @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
*
* Returns the decoder's video CAPTURE parameters.
*/
static int
-ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_captureparm *cparm;
enum tvp514x_std current_std;
@@ -1099,13 +1115,14 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
memset(a, 0, sizeof(*a));
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1120,17 +1137,17 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
}
/**
- * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm
+ * @sd: pointer to standard V4L2 sub-device structure
* @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
*
* Configures the decoder to use the input parameters, if possible. If
* not possible, returns the appropriate error code.
*/
static int
-ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_fract *timeperframe;
enum tvp514x_std current_std;
@@ -1138,12 +1155,13 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
timeperframe = &a->parm.capture.timeperframe;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1156,111 +1174,58 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
}
/**
- * ioctl_g_ifparm - V4L2 decoder interface handler for vidioc_int_g_ifparm_num
- * @s: pointer to standard V4L2 device structure
- * @p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
- *
- * Gets slave interface parameters.
- * Calculates the required xclk value to support the requested
- * clock parameters in p. This value is returned in the p
- * parameter.
- */
-static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
-{
- struct tvp514x_decoder *decoder = s->priv;
- int rval;
-
- if (p == NULL)
- return -EINVAL;
-
- if (NULL == decoder->pdata->ifparm)
- return -EINVAL;
-
- rval = decoder->pdata->ifparm(p);
- if (rval) {
- v4l_err(decoder->client, "g_ifparm.Err[%d]\n", rval);
- return rval;
- }
-
- p->u.bt656.clock_curr = TVP514X_XCLK_BT656;
-
- return 0;
-}
-
-/**
- * ioctl_g_priv - V4L2 decoder interface handler for vidioc_int_g_priv_num
- * @s: pointer to standard V4L2 device structure
- * @p: void pointer to hold decoder's private data address
- *
- * Returns device's (decoder's) private data area address in p parameter
- */
-static int ioctl_g_priv(struct v4l2_int_device *s, void *p)
-{
- struct tvp514x_decoder *decoder = s->priv;
-
- if (NULL == decoder->pdata->priv_data_set)
- return -EINVAL;
-
- return decoder->pdata->priv_data_set(p);
-}
-
-/**
- * ioctl_s_power - V4L2 decoder interface handler for vidioc_int_s_power_num
- * @s: pointer to standard V4L2 device structure
- * @on: power state to which device is to be set
+ * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
*
- * Sets devices power state to requrested state, if possible.
+ * Sets streaming to enable or disable, if possible.
*/
-static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct tvp514x_decoder *decoder = s->priv;
int err = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
- switch (on) {
- case V4L2_POWER_OFF:
- /* Power Down Sequence */
- err =
- tvp514x_write_reg(decoder->client, REG_OPERATION_MODE,
- 0x01);
- /* Disable mux for TVP5146/47 decoder data path */
- if (decoder->pdata->power_set)
- err |= decoder->pdata->power_set(on);
- decoder->state = STATE_NOT_DETECTED;
- break;
+ if (decoder->streaming == enable)
+ return 0;
- case V4L2_POWER_STANDBY:
- if (decoder->pdata->power_set)
- err = decoder->pdata->power_set(on);
+ switch (enable) {
+ case 0:
+ {
+ /* Power Down Sequence */
+ err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01);
+ if (err) {
+ v4l2_err(sd, "Unable to turn off decoder\n");
+ return err;
+ }
+ decoder->streaming = enable;
break;
+ }
+ case 1:
+ {
+ struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
+ client->driver->id_table->driver_data;
- case V4L2_POWER_ON:
- /* Enable mux for TVP5146/47 decoder data path */
- if ((decoder->pdata->power_set) &&
- (decoder->state == STATE_NOT_DETECTED)) {
- int i;
- struct tvp514x_init_seq *int_seq =
- (struct tvp514x_init_seq *)
- decoder->id->driver_data;
-
- err = decoder->pdata->power_set(on);
-
- /* Power Up Sequence */
- for (i = 0; i < int_seq->no_regs; i++) {
- err |= tvp514x_write_reg(decoder->client,
- int_seq->init_reg_seq[i].reg,
- int_seq->init_reg_seq[i].val);
- }
- /* Detect the sensor is not already detected */
- err |= tvp514x_detect(decoder);
- if (err) {
- v4l_err(decoder->client,
- "Unable to detect decoder\n");
- return err;
- }
+ /* Power Up Sequence */
+ err = tvp514x_write_regs(sd, int_seq);
+ if (err) {
+ v4l2_err(sd, "Unable to turn on decoder\n");
+ return err;
}
- err |= tvp514x_configure(decoder);
+ /* Detect if not already detected */
+ err = tvp514x_detect(sd, decoder);
+ if (err) {
+ v4l2_err(sd, "Unable to detect decoder\n");
+ return err;
+ }
+ err = tvp514x_configure(sd, decoder);
+ if (err) {
+ v4l2_err(sd, "Unable to configure decoder\n");
+ return err;
+ }
+ decoder->streaming = enable;
break;
-
+ }
default:
err = -ENODEV;
break;
@@ -1269,93 +1234,38 @@ static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
return err;
}
-/**
- * ioctl_init - V4L2 decoder interface handler for VIDIOC_INT_INIT
- * @s: pointer to standard V4L2 device structure
- *
- * Initialize the decoder device (calls tvp514x_configure())
- */
-static int ioctl_init(struct v4l2_int_device *s)
-{
- struct tvp514x_decoder *decoder = s->priv;
-
- /* Set default standard to auto */
- decoder->tvp514x_regs[REG_VIDEO_STD].val =
- VIDEO_STD_AUTO_SWITCH_BIT;
-
- return tvp514x_configure(decoder);
-}
-
-/**
- * ioctl_dev_exit - V4L2 decoder interface handler for vidioc_int_dev_exit_num
- * @s: pointer to standard V4L2 device structure
- *
- * Delinitialise the dev. at slave detach. The complement of ioctl_dev_init.
- */
-static int ioctl_dev_exit(struct v4l2_int_device *s)
-{
- return 0;
-}
-
-/**
- * ioctl_dev_init - V4L2 decoder interface handler for vidioc_int_dev_init_num
- * @s: pointer to standard V4L2 device structure
- *
- * Initialise the device when slave attaches to the master. Returns 0 if
- * TVP5146/47 device could be found, otherwise returns appropriate error.
- */
-static int ioctl_dev_init(struct v4l2_int_device *s)
-{
- struct tvp514x_decoder *decoder = s->priv;
- int err;
-
- err = tvp514x_detect(decoder);
- if (err < 0) {
- v4l_err(decoder->client,
- "Unable to detect decoder\n");
- return err;
- }
-
- v4l_info(decoder->client,
- "chip version 0x%.2x detected\n", decoder->ver);
+static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
+ .queryctrl = tvp514x_queryctrl,
+ .g_ctrl = tvp514x_g_ctrl,
+ .s_ctrl = tvp514x_s_ctrl,
+ .s_std = tvp514x_s_std,
+};
- return 0;
-}
+static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
+ .s_routing = tvp514x_s_routing,
+ .querystd = tvp514x_querystd,
+ .enum_fmt = tvp514x_enum_fmt_cap,
+ .g_fmt = tvp514x_g_fmt_cap,
+ .try_fmt = tvp514x_try_fmt_cap,
+ .s_fmt = tvp514x_s_fmt_cap,
+ .g_parm = tvp514x_g_parm,
+ .s_parm = tvp514x_s_parm,
+ .s_stream = tvp514x_s_stream,
+};
-static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = {
- {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*) ioctl_dev_init},
- {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func*) ioctl_dev_exit},
- {vidioc_int_s_power_num, (v4l2_int_ioctl_func*) ioctl_s_power},
- {vidioc_int_g_priv_num, (v4l2_int_ioctl_func*) ioctl_g_priv},
- {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*) ioctl_g_ifparm},
- {vidioc_int_init_num, (v4l2_int_ioctl_func*) ioctl_init},
- {vidioc_int_enum_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap},
- {vidioc_int_try_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_try_fmt_cap},
- {vidioc_int_g_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_g_fmt_cap},
- {vidioc_int_s_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_s_fmt_cap},
- {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm},
- {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm},
- {vidioc_int_queryctrl_num,
- (v4l2_int_ioctl_func *) ioctl_queryctrl},
- {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl},
- {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl},
- {vidioc_int_querystd_num, (v4l2_int_ioctl_func *) ioctl_querystd},
- {vidioc_int_s_std_num, (v4l2_int_ioctl_func *) ioctl_s_std},
- {vidioc_int_s_video_routing_num,
- (v4l2_int_ioctl_func *) ioctl_s_routing},
+static const struct v4l2_subdev_ops tvp514x_ops = {
+ .core = &tvp514x_core_ops,
+ .video = &tvp514x_video_ops,
};
static struct tvp514x_decoder tvp514x_dev = {
- .state = STATE_NOT_DETECTED,
+ .streaming = 0,
.fmt_list = tvp514x_fmt_list,
.num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
- .pix = { /* Default to NTSC 8-bit YUV 422 */
+ .pix = {
+ /* Default to NTSC 8-bit YUV 422 */
.width = NTSC_NUM_ACTIVE_PIXELS,
.height = NTSC_NUM_ACTIVE_LINES,
.pixelformat = V4L2_PIX_FMT_UYVY,
@@ -1369,20 +1279,13 @@ static struct tvp514x_decoder tvp514x_dev = {
.current_std = STD_NTSC_MJ,
.std_list = tvp514x_std_list,
.num_stds = ARRAY_SIZE(tvp514x_std_list),
- .v4l2_int_device = {
- .module = THIS_MODULE,
- .name = TVP514X_MODULE_NAME,
- .type = v4l2_int_type_slave,
- },
- .tvp514x_slave = {
- .ioctls = tvp514x_ioctl_desc,
- .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
- },
+
};
/**
- * tvp514x_probe - decoder driver i2c probe handler
+ * tvp514x_probe() - decoder driver i2c probe handler
* @client: i2c driver client device structure
+ * @id: i2c driver id table
*
* Register decoder as an i2c client device and V4L2
* device.
@@ -1391,88 +1294,71 @@ static int
tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct tvp514x_decoder *decoder;
- int err;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+ if (!client->dev.platform_data) {
+ v4l2_err(client, "No platform data!!\n");
+ return -ENODEV;
+ }
+
decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
- if (!client->dev.platform_data) {
- v4l_err(client, "No platform data!!\n");
- err = -ENODEV;
- goto out_free;
- }
-
+ /* Initialize the tvp514x_decoder with default configuration */
*decoder = tvp514x_dev;
- decoder->v4l2_int_device.priv = decoder;
- decoder->pdata = client->dev.platform_data;
- decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave;
+ /* Copy default register configuration */
memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
sizeof(tvp514x_reg_list_default));
- /*
+
+ /* Copy board specific information here */
+ decoder->pdata = client->dev.platform_data;
+
+ /**
* Fetch platform specific data, and configure the
* tvp514x_reg_list[] accordingly. Since this is one
* time configuration, no need to preserve.
*/
decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
- (decoder->pdata->clk_polarity << 1);
+ (decoder->pdata->clk_polarity << 1);
decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
- ((decoder->pdata->hs_polarity << 2) |
- (decoder->pdata->vs_polarity << 3));
- /*
- * Save the id data, required for power up sequence
- */
- decoder->id = (struct i2c_device_id *)id;
- /* Attach to Master */
- strcpy(decoder->v4l2_int_device.u.slave->attach_to,
- decoder->pdata->master);
- decoder->client = client;
- i2c_set_clientdata(client, decoder);
+ ((decoder->pdata->hs_polarity << 2) |
+ (decoder->pdata->vs_polarity << 3));
+ /* Set default standard to auto */
+ decoder->tvp514x_regs[REG_VIDEO_STD].val =
+ VIDEO_STD_AUTO_SWITCH_BIT;
/* Register with V4L2 layer as slave device */
- err = v4l2_int_device_register(&decoder->v4l2_int_device);
- if (err) {
- i2c_set_clientdata(client, NULL);
- v4l_err(client,
- "Unable to register to v4l2. Err[%d]\n", err);
- goto out_free;
-
- } else
- v4l_info(client, "Registered to v4l2 master %s!!\n",
- decoder->pdata->master);
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
+
+ v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
+
return 0;
-out_free:
- kfree(decoder);
- return err;
}
/**
- * tvp514x_remove - decoder driver i2c remove handler
+ * tvp514x_remove() - decoder driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister decoder as an i2c client device and V4L2
* device. Complement of tvp514x_probe().
*/
-static int __exit tvp514x_remove(struct i2c_client *client)
+static int tvp514x_remove(struct i2c_client *client)
{
- struct tvp514x_decoder *decoder = i2c_get_clientdata(client);
-
- if (!client->adapter)
- return -ENODEV; /* our client isn't attached */
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
- v4l2_int_device_unregister(&decoder->v4l2_int_device);
- i2c_set_clientdata(client, NULL);
+ v4l2_device_unregister_subdev(sd);
kfree(decoder);
return 0;
}
-/*
- * TVP5146 Init/Power on Sequence
- */
+/* TVP5146 Init/Power on Sequence */
static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
@@ -1485,14 +1371,10 @@ static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
};
-static const struct tvp514x_init_seq tvp5146_init = {
- .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
- .init_reg_seq = tvp5146_init_reg_seq,
-};
-/*
- * TVP5147 Init/Power on Sequence
- */
+
+/* TVP5147 Init/Power on Sequence */
static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
@@ -1512,71 +1394,51 @@ static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
};
-static const struct tvp514x_init_seq tvp5147_init = {
- .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
- .init_reg_seq = tvp5147_init_reg_seq,
-};
-/*
- * TVP5146M2/TVP5147M1 Init/Power on Sequence
- */
+
+/* TVP5146M2/TVP5147M1 Init/Power on Sequence */
static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
};
-static const struct tvp514x_init_seq tvp514xm_init = {
- .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
- .init_reg_seq = tvp514xm_init_reg_seq,
-};
-/*
+
+/**
* I2C Device Table -
*
* name - Name of the actual device/chip.
* driver_data - Driver data
*/
static const struct i2c_device_id tvp514x_id[] = {
- {"tvp5146", (unsigned long)&tvp5146_init},
- {"tvp5146m2", (unsigned long)&tvp514xm_init},
- {"tvp5147", (unsigned long)&tvp5147_init},
- {"tvp5147m1", (unsigned long)&tvp514xm_init},
+ {"tvp5146", (unsigned long)tvp5146_init_reg_seq},
+ {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq},
+ {"tvp5147", (unsigned long)tvp5147_init_reg_seq},
+ {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq},
{},
};
MODULE_DEVICE_TABLE(i2c, tvp514x_id);
-static struct i2c_driver tvp514x_i2c_driver = {
+static struct i2c_driver tvp514x_driver = {
.driver = {
- .name = TVP514X_MODULE_NAME,
- .owner = THIS_MODULE,
- },
+ .owner = THIS_MODULE,
+ .name = TVP514X_MODULE_NAME,
+ },
.probe = tvp514x_probe,
- .remove = __exit_p(tvp514x_remove),
+ .remove = tvp514x_remove,
.id_table = tvp514x_id,
};
-/**
- * tvp514x_init
- *
- * Module init function
- */
static int __init tvp514x_init(void)
{
- return i2c_add_driver(&tvp514x_i2c_driver);
+ return i2c_add_driver(&tvp514x_driver);
}
-/**
- * tvp514x_cleanup
- *
- * Module exit function
- */
-static void __exit tvp514x_cleanup(void)
+static void __exit tvp514x_exit(void)
{
- i2c_del_driver(&tvp514x_i2c_driver);
+ i2c_del_driver(&tvp514x_driver);
}
module_init(tvp514x_init);
-module_exit(tvp514x_cleanup);
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("TVP514X linux decoder driver");
-MODULE_LICENSE("GPL");
+module_exit(tvp514x_exit);
diff --git a/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h
index 351620aeecc2..18f29ad0dfe2 100644
--- a/drivers/media/video/tvp514x_regs.h
+++ b/drivers/media/video/tvp514x_regs.h
@@ -284,14 +284,4 @@ struct tvp514x_reg {
u32 val;
};
-/**
- * struct tvp514x_init_seq - Structure for TVP5146/47/46M2/47M1 power up
- * Sequence.
- * @ no_regs - Number of registers to write for power up sequence.
- * @ init_reg_seq - Array of registers and respective value to write.
- */
-struct tvp514x_init_seq {
- unsigned int no_regs;
- const struct tvp514x_reg *init_reg_seq;
-};
#endif /* ifndef _TVP514X_REGS_H */
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index aa5065ea09ed..269ab044072a 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -24,7 +24,7 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
#include <media/tw9910.h>
@@ -223,9 +223,8 @@ struct tw9910_hsync_ctrl {
};
struct tw9910_priv {
+ struct v4l2_subdev subdev;
struct tw9910_video_info *info;
- struct i2c_client *client;
- struct soc_camera_device icd;
const struct tw9910_scale_ctrl *scale;
};
@@ -356,6 +355,12 @@ static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = {
/*
* general function
*/
+static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct tw9910_priv,
+ subdev);
+}
+
static int tw9910_set_scale(struct i2c_client *client,
const struct tw9910_scale_ctrl *scale)
{
@@ -509,44 +514,20 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
/*
* soc_camera_ops function
*/
-static int tw9910_init(struct soc_camera_device *icd)
-{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
- int ret = 0;
-
- if (priv->info->link.power) {
- ret = priv->info->link.power(&priv->client->dev, 1);
- if (ret < 0)
- return ret;
- }
-
- if (priv->info->link.reset)
- ret = priv->info->link.reset(&priv->client->dev);
-
- return ret;
-}
-
-static int tw9910_release(struct soc_camera_device *icd)
+static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
- int ret = 0;
-
- if (priv->info->link.power)
- ret = priv->info->link.power(&priv->client->dev, 0);
-
- return ret;
-}
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
-static int tw9910_start_capture(struct soc_camera_device *icd)
-{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ if (!enable)
+ return 0;
if (!priv->scale) {
- dev_err(&icd->dev, "norm select error\n");
+ dev_err(&client->dev, "norm select error\n");
return -EPERM;
}
- dev_dbg(&icd->dev, "%s %dx%d\n",
+ dev_dbg(&client->dev, "%s %dx%d\n",
priv->scale->name,
priv->scale->width,
priv->scale->height);
@@ -554,11 +535,6 @@ static int tw9910_start_capture(struct soc_camera_device *icd)
return 0;
}
-static int tw9910_stop_capture(struct soc_camera_device *icd)
-{
- return 0;
-}
-
static int tw9910_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
@@ -567,8 +543,9 @@ static int tw9910_set_bus_param(struct soc_camera_device *icd,
static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
- struct soc_camera_link *icl = priv->client->dev.platform_data;
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
@@ -576,21 +553,11 @@ static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
return soc_camera_apply_sensor_flags(icl, flags);
}
-static int tw9910_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
-{
- id->ident = V4L2_IDENT_TW9910;
- id->revision = 0;
-
- return 0;
-}
-
-static int tw9910_set_std(struct soc_camera_device *icd,
- v4l2_std_id *a)
+static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
{
int ret = -EINVAL;
- if (*a & (V4L2_STD_NTSC | V4L2_STD_PAL))
+ if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL))
ret = 0;
return ret;
@@ -606,17 +573,26 @@ static int tw9910_enum_input(struct soc_camera_device *icd,
return 0;
}
+static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ id->ident = V4L2_IDENT_TW9910;
+ id->revision = 0;
+
+ return 0;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int tw9910_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int tw9910_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct i2c_client *client = sd->priv;
int ret;
if (reg->reg > 0xff)
return -EINVAL;
- ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
if (ret < 0)
return ret;
@@ -628,23 +604,25 @@ static int tw9910_get_register(struct soc_camera_device *icd,
return 0;
}
-static int tw9910_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int tw9910_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct i2c_client *client = sd->priv;
if (reg->reg > 0xff ||
reg->val > 0xff)
return -EINVAL;
- return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
}
#endif
-static int tw9910_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct v4l2_rect *rect = &a->c;
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
int ret = -EINVAL;
u8 val;
@@ -658,8 +636,8 @@ static int tw9910_set_crop(struct soc_camera_device *icd,
/*
* reset hardware
*/
- tw9910_reset(priv->client);
- ret = tw9910_write_array(priv->client, tw9910_default_regs);
+ tw9910_reset(client);
+ ret = tw9910_write_array(client, tw9910_default_regs);
if (ret < 0)
goto tw9910_set_fmt_error;
@@ -670,7 +648,7 @@ static int tw9910_set_crop(struct soc_camera_device *icd,
if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
val = LEN;
- ret = tw9910_mask_set(priv->client, OPFORM, LEN, val);
+ ret = tw9910_mask_set(client, OPFORM, LEN, val);
if (ret < 0)
goto tw9910_set_fmt_error;
@@ -698,52 +676,139 @@ static int tw9910_set_crop(struct soc_camera_device *icd,
val = 0;
}
- ret = tw9910_mask_set(priv->client, VBICNTL, RTSEL_MASK, val);
+ ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
if (ret < 0)
goto tw9910_set_fmt_error;
/*
* set scale
*/
- ret = tw9910_set_scale(priv->client, priv->scale);
+ ret = tw9910_set_scale(client, priv->scale);
if (ret < 0)
goto tw9910_set_fmt_error;
/*
* set cropping
*/
- ret = tw9910_set_cropping(priv->client, &tw9910_cropping_ctrl);
+ ret = tw9910_set_cropping(client, &tw9910_cropping_ctrl);
if (ret < 0)
goto tw9910_set_fmt_error;
/*
* set hsync
*/
- ret = tw9910_set_hsync(priv->client, &tw9910_hsync_ctrl);
+ ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl);
if (ret < 0)
goto tw9910_set_fmt_error;
+ rect->width = priv->scale->width;
+ rect->height = priv->scale->height;
+ rect->left = 0;
+ rect->top = 0;
+
return ret;
tw9910_set_fmt_error:
- tw9910_reset(priv->client);
+ tw9910_reset(client);
priv->scale = NULL;
return ret;
}
-static int tw9910_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ if (!priv->scale) {
+ int ret;
+ struct v4l2_crop crop = {
+ .c = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ };
+ ret = tw9910_s_crop(sd, &crop);
+ if (ret < 0)
+ return ret;
+ }
+
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = priv->scale->width;
+ a->c.height = priv->scale->height;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = 768;
+ a->bounds.height = 576;
+ a->defrect.left = 0;
+ a->defrect.top = 0;
+ a->defrect.width = 640;
+ a->defrect.height = 480;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (!priv->scale) {
+ int ret;
+ struct v4l2_crop crop = {
+ .c = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ };
+ ret = tw9910_s_crop(sd, &crop);
+ if (ret < 0)
+ return ret;
+ }
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ pix->width = priv->scale->width;
+ pix->height = priv->scale->height;
+ pix->pixelformat = V4L2_PIX_FMT_VYUY;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->field = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = pix->width,
- .height = pix->height,
+ /* See tw9910_s_crop() - no proper cropping support */
+ struct v4l2_crop a = {
+ .c = {
+ .left = 0,
+ .top = 0,
+ .width = pix->width,
+ .height = pix->height,
+ },
};
- int i;
+ int i, ret;
/*
* check color format
@@ -755,19 +820,25 @@ static int tw9910_set_fmt(struct soc_camera_device *icd,
if (i == ARRAY_SIZE(tw9910_color_fmt))
return -EINVAL;
- return tw9910_set_crop(icd, &rect);
+ ret = tw9910_s_crop(sd, &a);
+ if (!ret) {
+ pix->width = priv->scale->width;
+ pix->height = priv->scale->height;
+ }
+ return ret;
}
-static int tw9910_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
+ struct i2c_client *client = sd->priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
const struct tw9910_scale_ctrl *scale;
if (V4L2_FIELD_ANY == pix->field) {
pix->field = V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != pix->field) {
- dev_err(&icd->dev, "Field type invalid.\n");
+ dev_err(&client->dev, "Field type invalid.\n");
return -EINVAL;
}
@@ -784,11 +855,11 @@ static int tw9910_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int tw9910_video_probe(struct soc_camera_device *icd)
+static int tw9910_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct tw9910_priv *priv = to_tw9910(client);
s32 val;
- int ret;
/*
* We must have a parent by now. And it cannot be a wrong one.
@@ -803,7 +874,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd)
*/
if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
- dev_err(&icd->dev, "bus width error\n");
+ dev_err(&client->dev, "bus width error\n");
return -ENODEV;
}
@@ -813,54 +884,54 @@ static int tw9910_video_probe(struct soc_camera_device *icd)
/*
* check and show Product ID
*/
- val = i2c_smbus_read_byte_data(priv->client, ID);
+ val = i2c_smbus_read_byte_data(client, ID);
+
if (0x0B != GET_ID(val) ||
0x00 != GET_ReV(val)) {
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"Product ID error %x:%x\n", GET_ID(val), GET_ReV(val));
return -ENODEV;
}
- dev_info(&icd->dev,
+ dev_info(&client->dev,
"tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val));
- ret = soc_camera_video_start(icd);
- if (ret < 0)
- return ret;
-
icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL;
icd->vdev->current_norm = V4L2_STD_NTSC;
- return ret;
-}
-
-static void tw9910_video_remove(struct soc_camera_device *icd)
-{
- soc_camera_video_stop(icd);
+ return 0;
}
static struct soc_camera_ops tw9910_ops = {
- .owner = THIS_MODULE,
- .probe = tw9910_video_probe,
- .remove = tw9910_video_remove,
- .init = tw9910_init,
- .release = tw9910_release,
- .start_capture = tw9910_start_capture,
- .stop_capture = tw9910_stop_capture,
- .set_crop = tw9910_set_crop,
- .set_fmt = tw9910_set_fmt,
- .try_fmt = tw9910_try_fmt,
.set_bus_param = tw9910_set_bus_param,
.query_bus_param = tw9910_query_bus_param,
- .get_chip_id = tw9910_get_chip_id,
- .set_std = tw9910_set_std,
.enum_input = tw9910_enum_input,
+};
+
+static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
+ .g_chip_ident = tw9910_g_chip_ident,
+ .s_std = tw9910_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = tw9910_get_register,
- .set_register = tw9910_set_register,
+ .g_register = tw9910_g_register,
+ .s_register = tw9910_s_register,
#endif
};
+static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
+ .s_stream = tw9910_s_stream,
+ .g_fmt = tw9910_g_fmt,
+ .s_fmt = tw9910_s_fmt,
+ .try_fmt = tw9910_try_fmt,
+ .cropcap = tw9910_cropcap,
+ .g_crop = tw9910_g_crop,
+ .s_crop = tw9910_s_crop,
+};
+
+static struct v4l2_subdev_ops tw9910_subdev_ops = {
+ .core = &tw9910_subdev_core_ops,
+ .video = &tw9910_subdev_video_ops,
+};
+
/*
* i2c_driver function
*/
@@ -871,18 +942,24 @@ static int tw9910_probe(struct i2c_client *client,
{
struct tw9910_priv *priv;
struct tw9910_video_info *info;
- struct soc_camera_device *icd;
- const struct tw9910_scale_ctrl *scale;
- int i, ret;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct i2c_adapter *adapter =
+ to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl;
+ int ret;
+
+ if (!icd) {
+ dev_err(&client->dev, "TW9910: missing soc-camera data!\n");
+ return -EINVAL;
+ }
- if (!client->dev.platform_data)
+ icl = to_soc_camera_link(icd);
+ if (!icl)
return -EINVAL;
- info = container_of(client->dev.platform_data,
- struct tw9910_video_info, link);
+ info = container_of(icl, struct tw9910_video_info, link);
- if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
- I2C_FUNC_SMBUS_BYTE_DATA)) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev,
"I2C-Adapter doesn't support "
"I2C_FUNC_SMBUS_BYTE_DATA\n");
@@ -894,40 +971,15 @@ static int tw9910_probe(struct i2c_client *client,
return -ENOMEM;
priv->info = info;
- priv->client = client;
- i2c_set_clientdata(client, priv);
- icd = &priv->icd;
+ v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
+
icd->ops = &tw9910_ops;
- icd->control = &client->dev;
icd->iface = info->link.bus_id;
- /*
- * set width and height
- */
- icd->width_max = tw9910_ntsc_scales[0].width; /* set default */
- icd->width_min = tw9910_ntsc_scales[0].width;
- icd->height_max = tw9910_ntsc_scales[0].height;
- icd->height_min = tw9910_ntsc_scales[0].height;
-
- scale = tw9910_ntsc_scales;
- for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) {
- icd->width_max = max(scale[i].width, icd->width_max);
- icd->width_min = min(scale[i].width, icd->width_min);
- icd->height_max = max(scale[i].height, icd->height_max);
- icd->height_min = min(scale[i].height, icd->height_min);
- }
- scale = tw9910_pal_scales;
- for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) {
- icd->width_max = max(scale[i].width, icd->width_max);
- icd->width_min = min(scale[i].width, icd->width_min);
- icd->height_max = max(scale[i].height, icd->height_max);
- icd->height_min = min(scale[i].height, icd->height_min);
- }
-
- ret = soc_camera_device_register(icd);
-
+ ret = tw9910_video_probe(icd, client);
if (ret) {
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -937,9 +989,10 @@ static int tw9910_probe(struct i2c_client *client,
static int tw9910_remove(struct i2c_client *client)
{
- struct tw9910_priv *priv = i2c_get_clientdata(client);
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&priv->icd);
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 36a6ba92df27..c3225a561748 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -34,7 +34,7 @@
static struct uvc_control_info uvc_ctrls[] = {
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BRIGHTNESS_CONTROL,
+ .selector = UVC_PU_BRIGHTNESS_CONTROL,
.index = 0,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -42,7 +42,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_CONTRAST_CONTROL,
+ .selector = UVC_PU_CONTRAST_CONTROL,
.index = 1,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -50,7 +50,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_CONTROL,
+ .selector = UVC_PU_HUE_CONTROL,
.index = 2,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -58,7 +58,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SATURATION_CONTROL,
+ .selector = UVC_PU_SATURATION_CONTROL,
.index = 3,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -66,7 +66,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SHARPNESS_CONTROL,
+ .selector = UVC_PU_SHARPNESS_CONTROL,
.index = 4,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -74,7 +74,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAMMA_CONTROL,
+ .selector = UVC_PU_GAMMA_CONTROL,
.index = 5,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -82,7 +82,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
.index = 6,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -90,7 +90,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.index = 7,
.size = 4,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -98,7 +98,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
.index = 8,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -106,7 +106,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAIN_CONTROL,
+ .selector = UVC_PU_GAIN_CONTROL,
.index = 9,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -114,7 +114,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.index = 10,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -122,7 +122,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_AUTO_CONTROL,
+ .selector = UVC_PU_HUE_AUTO_CONTROL,
.index = 11,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -130,7 +130,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
.index = 12,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -138,7 +138,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
.index = 13,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -146,7 +146,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_DIGITAL_MULTIPLIER_CONTROL,
+ .selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL,
.index = 14,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -154,7 +154,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
+ .selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
.index = 15,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -162,21 +162,21 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_ANALOG_VIDEO_STANDARD_CONTROL,
+ .selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL,
.index = 16,
.size = 1,
.flags = UVC_CONTROL_GET_CUR,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_ANALOG_LOCK_STATUS_CONTROL,
+ .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL,
.index = 17,
.size = 1,
.flags = UVC_CONTROL_GET_CUR,
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_SCANNING_MODE_CONTROL,
+ .selector = UVC_CT_SCANNING_MODE_CONTROL,
.index = 0,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -184,7 +184,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_MODE_CONTROL,
+ .selector = UVC_CT_AE_MODE_CONTROL,
.index = 1,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -193,7 +193,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_PRIORITY_CONTROL,
+ .selector = UVC_CT_AE_PRIORITY_CONTROL,
.index = 2,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -201,7 +201,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
.index = 3,
.size = 4,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -209,7 +209,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_EXPOSURE_TIME_RELATIVE_CONTROL,
+ .selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
.index = 4,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -217,7 +217,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
.index = 5,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -225,7 +225,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_RELATIVE_CONTROL,
+ .selector = UVC_CT_FOCUS_RELATIVE_CONTROL,
.index = 6,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -233,7 +233,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_IRIS_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL,
.index = 7,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -241,7 +241,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_IRIS_RELATIVE_CONTROL,
+ .selector = UVC_CT_IRIS_RELATIVE_CONTROL,
.index = 8,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -249,7 +249,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
.index = 9,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -257,7 +257,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_RELATIVE_CONTROL,
+ .selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
.index = 10,
.size = 3,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -265,7 +265,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PANTILT_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
.index = 11,
.size = 8,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -273,7 +273,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PANTILT_RELATIVE_CONTROL,
+ .selector = UVC_CT_PANTILT_RELATIVE_CONTROL,
.index = 12,
.size = 4,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -281,7 +281,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ROLL_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_ROLL_ABSOLUTE_CONTROL,
.index = 13,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -289,7 +289,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ROLL_RELATIVE_CONTROL,
+ .selector = UVC_CT_ROLL_RELATIVE_CONTROL,
.index = 14,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -297,7 +297,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_AUTO_CONTROL,
+ .selector = UVC_CT_FOCUS_AUTO_CONTROL,
.index = 17,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -305,7 +305,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PRIVACY_CONTROL,
+ .selector = UVC_CT_PRIVACY_CONTROL,
.index = 18,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -332,13 +332,13 @@ static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
__s8 zoom = (__s8)data[0];
switch (query) {
- case GET_CUR:
+ case UVC_GET_CUR:
return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
- case GET_MIN:
- case GET_MAX:
- case GET_RES:
- case GET_DEF:
+ case UVC_GET_MIN:
+ case UVC_GET_MAX:
+ case UVC_GET_RES:
+ case UVC_GET_DEF:
default:
return data[2];
}
@@ -356,7 +356,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_BRIGHTNESS,
.name = "Brightness",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BRIGHTNESS_CONTROL,
+ .selector = UVC_PU_BRIGHTNESS_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -366,7 +366,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_CONTRAST,
.name = "Contrast",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_CONTRAST_CONTROL,
+ .selector = UVC_PU_CONTRAST_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -376,7 +376,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_HUE,
.name = "Hue",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_CONTROL,
+ .selector = UVC_PU_HUE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -386,7 +386,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_SATURATION,
.name = "Saturation",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SATURATION_CONTROL,
+ .selector = UVC_PU_SATURATION_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -396,7 +396,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_SHARPNESS,
.name = "Sharpness",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SHARPNESS_CONTROL,
+ .selector = UVC_PU_SHARPNESS_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -406,7 +406,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_GAMMA,
.name = "Gamma",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAMMA_CONTROL,
+ .selector = UVC_PU_GAMMA_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -416,7 +416,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_BACKLIGHT_COMPENSATION,
.name = "Backlight Compensation",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -426,7 +426,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_GAIN,
.name = "Gain",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAIN_CONTROL,
+ .selector = UVC_PU_GAIN_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -436,7 +436,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.name = "Power Line Frequency",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.size = 2,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_MENU,
@@ -448,7 +448,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_HUE_AUTO,
.name = "Hue, Auto",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_AUTO_CONTROL,
+ .selector = UVC_PU_HUE_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -458,7 +458,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_EXPOSURE_AUTO,
.name = "Exposure, Auto",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_MODE_CONTROL,
+ .selector = UVC_CT_AE_MODE_CONTROL,
.size = 4,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_MENU,
@@ -470,7 +470,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
.name = "Exposure, Auto Priority",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_PRIORITY_CONTROL,
+ .selector = UVC_CT_AE_PRIORITY_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -480,7 +480,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_EXPOSURE_ABSOLUTE,
.name = "Exposure (Absolute)",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
.size = 32,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -490,7 +490,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.name = "White Balance Temperature, Auto",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -500,7 +500,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
.name = "White Balance Temperature",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -510,7 +510,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.name = "White Balance Component, Auto",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -520,7 +520,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_BLUE_BALANCE,
.name = "White Balance Blue Component",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -530,7 +530,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_RED_BALANCE,
.name = "White Balance Red Component",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.size = 16,
.offset = 16,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -540,7 +540,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_FOCUS_ABSOLUTE,
.name = "Focus (absolute)",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -550,7 +550,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_FOCUS_AUTO,
.name = "Focus, Auto",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_AUTO_CONTROL,
+ .selector = UVC_CT_FOCUS_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -560,7 +560,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_ZOOM_ABSOLUTE,
.name = "Zoom, Absolute",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -570,7 +570,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_ZOOM_CONTINUOUS,
.name = "Zoom, Continuous",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_RELATIVE_CONTROL,
+ .selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
.size = 0,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -582,7 +582,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_PRIVACY,
.name = "Privacy",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PRIVACY_CONTROL,
+ .selector = UVC_CT_PRIVACY_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -675,16 +675,16 @@ static const __u8 uvc_media_transport_input_guid[16] =
static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
{
switch (UVC_ENTITY_TYPE(entity)) {
- case ITT_CAMERA:
+ case UVC_ITT_CAMERA:
return memcmp(uvc_camera_guid, guid, 16) == 0;
- case ITT_MEDIA_TRANSPORT_INPUT:
+ case UVC_ITT_MEDIA_TRANSPORT_INPUT:
return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
return memcmp(uvc_processing_guid, guid, 16) == 0;
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
return memcmp(entity->extension.guidExtensionCode,
guid, 16) == 0;
@@ -729,7 +729,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
}
}
-struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping)
{
struct uvc_control *ctrl = NULL;
@@ -742,17 +742,17 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video,
v4l2_id &= V4L2_CTRL_ID_MASK;
/* Find the control. */
- __uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next);
+ __uvc_find_control(chain->processing, v4l2_id, mapping, &ctrl, next);
if (ctrl && !next)
return ctrl;
- list_for_each_entry(entity, &video->iterms, chain) {
+ list_for_each_entry(entity, &chain->iterms, chain) {
__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
if (ctrl && !next)
return ctrl;
}
- list_for_each_entry(entity, &video->extensions, chain) {
+ list_for_each_entry(entity, &chain->extensions, chain) {
__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
if (ctrl && !next)
return ctrl;
@@ -765,7 +765,7 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video,
return ctrl;
}
-int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl)
{
struct uvc_control *ctrl;
@@ -775,7 +775,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
__u8 *data;
int ret;
- ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);
+ ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
if (ctrl == NULL)
return -EINVAL;
@@ -793,11 +793,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
- if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ data, ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data);
+ v4l2_ctrl->default_value =
+ mapping->get(mapping, UVC_GET_DEF, data);
}
switch (mapping->v4l2_type) {
@@ -829,25 +831,28 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
}
if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
- if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ data, ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data);
+ v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
- if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ data, ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data);
+ v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
- if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ data, ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->step = mapping->get(mapping, GET_RES, data);
+ v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
}
ret = 0;
@@ -881,9 +886,9 @@ out:
* (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
* control lock.
*/
-int uvc_ctrl_begin(struct uvc_video_device *video)
+int uvc_ctrl_begin(struct uvc_video_chain *chain)
{
- return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0;
+ return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
}
static int uvc_ctrl_commit_entity(struct uvc_device *dev,
@@ -912,7 +917,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
continue;
if (!rollback)
- ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,
+ ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
dev->intfnum, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size);
@@ -933,34 +938,34 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
return 0;
}
-int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback)
+int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
{
struct uvc_entity *entity;
int ret = 0;
/* Find the control. */
- ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback);
+ ret = uvc_ctrl_commit_entity(chain->dev, chain->processing, rollback);
if (ret < 0)
goto done;
- list_for_each_entry(entity, &video->iterms, chain) {
- ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+ list_for_each_entry(entity, &chain->iterms, chain) {
+ ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
if (ret < 0)
goto done;
}
- list_for_each_entry(entity, &video->extensions, chain) {
- ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+ list_for_each_entry(entity, &chain->extensions, chain) {
+ ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
if (ret < 0)
goto done;
}
done:
- mutex_unlock(&video->ctrl_mutex);
+ mutex_unlock(&chain->ctrl_mutex);
return ret;
}
-int uvc_ctrl_get(struct uvc_video_device *video,
+int uvc_ctrl_get(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl)
{
struct uvc_control *ctrl;
@@ -969,13 +974,13 @@ int uvc_ctrl_get(struct uvc_video_device *video,
unsigned int i;
int ret;
- ctrl = uvc_find_control(video, xctrl->id, &mapping);
+ ctrl = uvc_find_control(chain, xctrl->id, &mapping);
if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
return -EINVAL;
if (!ctrl->loaded) {
- ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size);
if (ret < 0)
@@ -984,7 +989,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
ctrl->loaded = 1;
}
- xctrl->value = mapping->get(mapping, GET_CUR,
+ xctrl->value = mapping->get(mapping, UVC_GET_CUR,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
@@ -1000,7 +1005,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
return 0;
}
-int uvc_ctrl_set(struct uvc_video_device *video,
+int uvc_ctrl_set(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl)
{
struct uvc_control *ctrl;
@@ -1008,7 +1013,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
s32 value = xctrl->value;
int ret;
- ctrl = uvc_find_control(video, xctrl->id, &mapping);
+ ctrl = uvc_find_control(chain, xctrl->id, &mapping);
if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
return -EINVAL;
@@ -1023,8 +1028,8 @@ int uvc_ctrl_set(struct uvc_video_device *video,
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
0, ctrl->info->size);
} else {
- ret = uvc_query_ctrl(video->dev, GET_CUR,
- ctrl->entity->id, video->dev->intfnum,
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
+ ctrl->entity->id, chain->dev->intfnum,
ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size);
@@ -1053,7 +1058,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
* Dynamic controls
*/
-int uvc_xu_ctrl_query(struct uvc_video_device *video,
+int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control *xctrl, int set)
{
struct uvc_entity *entity;
@@ -1063,7 +1068,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
int ret;
/* Find the extension unit. */
- list_for_each_entry(entity, &video->extensions, chain) {
+ list_for_each_entry(entity, &chain->extensions, chain) {
if (entity->id == xctrl->unit)
break;
}
@@ -1102,7 +1107,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
(!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
return -EINVAL;
- if (mutex_lock_interruptible(&video->ctrl_mutex))
+ if (mutex_lock_interruptible(&chain->ctrl_mutex))
return -ERESTARTSYS;
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
@@ -1115,9 +1120,9 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
goto out;
}
- ret = uvc_query_ctrl(video->dev, set ? SET_CUR : GET_CUR, xctrl->unit,
- video->dev->intfnum, xctrl->selector, data,
- xctrl->size);
+ ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
+ xctrl->unit, chain->dev->intfnum, xctrl->selector,
+ data, xctrl->size);
if (ret < 0)
goto out;
@@ -1132,7 +1137,7 @@ out:
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
xctrl->size);
- mutex_unlock(&video->ctrl_mutex);
+ mutex_unlock(&chain->ctrl_mutex);
return ret;
}
@@ -1211,7 +1216,7 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
if (!found)
return;
- if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
/* Check if the device control information and length match
* the user supplied information.
*/
@@ -1219,8 +1224,9 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
__le16 size;
__u8 inf;
- if ((ret = uvc_query_ctrl(dev, GET_LEN, ctrl->entity->id,
- dev->intfnum, info->selector, (__u8 *)&size, 2)) < 0) {
+ ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
+ dev->intfnum, info->selector, (__u8 *)&size, 2);
+ if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
"control " UVC_GUID_FORMAT "/%u (%d).\n",
UVC_GUID_ARGS(info->entity), info->selector,
@@ -1236,8 +1242,9 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
return;
}
- if ((ret = uvc_query_ctrl(dev, GET_INFO, ctrl->entity->id,
- dev->intfnum, info->selector, &inf, 1)) < 0) {
+ ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
+ dev->intfnum, info->selector, &inf, 1);
+ if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
"control " UVC_GUID_FORMAT "/%u (%d).\n",
UVC_GUID_ARGS(info->entity), info->selector,
@@ -1391,7 +1398,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
unsigned int size;
unsigned int i;
- if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+ if (UVC_ENTITY_TYPE(entity) != UVC_VC_PROCESSING_UNIT)
return;
controls = entity->processing.bmControls;
@@ -1427,13 +1434,13 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
unsigned int bControlSize = 0, ncontrols = 0;
__u8 *bmControls = NULL;
- if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
bmControls = entity->extension.bmControls;
bControlSize = entity->extension.bControlSize;
- } else if (UVC_ENTITY_TYPE(entity) == VC_PROCESSING_UNIT) {
+ } else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) {
bmControls = entity->processing.bmControls;
bControlSize = entity->processing.bControlSize;
- } else if (UVC_ENTITY_TYPE(entity) == ITT_CAMERA) {
+ } else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) {
bmControls = entity->camera.bmControls;
bControlSize = entity->camera.bControlSize;
}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 04b47832fa0a..8756be569154 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -249,23 +249,23 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
list_for_each_entry_continue(entity, &dev->entities, list) {
switch (UVC_ENTITY_TYPE(entity)) {
- case TT_STREAMING:
+ case UVC_TT_STREAMING:
if (entity->output.bSourceID == id)
return entity;
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
if (entity->processing.bSourceID == id)
return entity;
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
for (i = 0; i < entity->selector.bNrInPins; ++i)
if (entity->selector.baSourceID[i] == id)
return entity;
break;
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
for (i = 0; i < entity->extension.bNrInPins; ++i)
if (entity->extension.baSourceID[i] == id)
return entity;
@@ -276,8 +276,20 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
return NULL;
}
+static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
+{
+ struct uvc_streaming *stream;
+
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->header.bTerminalLink == id)
+ return stream;
+ }
+
+ return NULL;
+}
+
/* ------------------------------------------------------------------------
- * Descriptors handling
+ * Descriptors parsing
*/
static int uvc_parse_format(struct uvc_device *dev,
@@ -297,9 +309,9 @@ static int uvc_parse_format(struct uvc_device *dev,
format->index = buffer[3];
switch (buffer[2]) {
- case VS_FORMAT_UNCOMPRESSED:
- case VS_FORMAT_FRAME_BASED:
- n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_FRAME_BASED:
+ n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28;
if (buflen < n) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
@@ -325,16 +337,16 @@ static int uvc_parse_format(struct uvc_device *dev,
}
format->bpp = buffer[21];
- if (buffer[2] == VS_FORMAT_UNCOMPRESSED) {
- ftype = VS_FRAME_UNCOMPRESSED;
+ if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
+ ftype = UVC_VS_FRAME_UNCOMPRESSED;
} else {
- ftype = VS_FRAME_FRAME_BASED;
+ ftype = UVC_VS_FRAME_FRAME_BASED;
if (buffer[27])
format->flags = UVC_FMT_FLAG_COMPRESSED;
}
break;
- case VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_MJPEG:
if (buflen < 11) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
@@ -347,10 +359,10 @@ static int uvc_parse_format(struct uvc_device *dev,
format->fcc = V4L2_PIX_FMT_MJPEG;
format->flags = UVC_FMT_FLAG_COMPRESSED;
format->bpp = 0;
- ftype = VS_FRAME_MJPEG;
+ ftype = UVC_VS_FRAME_MJPEG;
break;
- case VS_FORMAT_DV:
+ case UVC_VS_FORMAT_DV:
if (buflen < 9) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
@@ -395,8 +407,8 @@ static int uvc_parse_format(struct uvc_device *dev,
format->nframes = 1;
break;
- case VS_FORMAT_MPEG2TS:
- case VS_FORMAT_STREAM_BASED:
+ case UVC_VS_FORMAT_MPEG2TS:
+ case UVC_VS_FORMAT_STREAM_BASED:
/* Not supported yet. */
default:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
@@ -416,7 +428,7 @@ static int uvc_parse_format(struct uvc_device *dev,
*/
while (buflen > 2 && buffer[2] == ftype) {
frame = &format->frame[format->nframes];
- if (ftype != VS_FRAME_FRAME_BASED)
+ if (ftype != UVC_VS_FRAME_FRAME_BASED)
n = buflen > 25 ? buffer[25] : 0;
else
n = buflen > 21 ? buffer[21] : 0;
@@ -436,7 +448,7 @@ static int uvc_parse_format(struct uvc_device *dev,
frame->wHeight = get_unaligned_le16(&buffer[7]);
frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
- if (ftype != VS_FRAME_FRAME_BASED) {
+ if (ftype != UVC_VS_FRAME_FRAME_BASED) {
frame->dwMaxVideoFrameBufferSize =
get_unaligned_le32(&buffer[17]);
frame->dwDefaultFrameInterval =
@@ -491,12 +503,12 @@ static int uvc_parse_format(struct uvc_device *dev,
buffer += buffer[0];
}
- if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {
+ if (buflen > 2 && buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
buflen -= buffer[0];
buffer += buffer[0];
}
- if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
+ if (buflen > 2 && buffer[2] == UVC_VS_COLORFORMAT) {
if (buflen < 6) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d COLORFORMAT error\n",
@@ -530,7 +542,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
int ret = -EINVAL;
if (intf->cur_altsetting->desc.bInterfaceSubClass
- != SC_VIDEOSTREAMING) {
+ != UVC_SC_VIDEOSTREAMING) {
uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
"video streaming interface\n", dev->udev->devnum,
intf->altsetting[0].desc.bInterfaceNumber);
@@ -551,6 +563,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
}
mutex_init(&streaming->mutex);
+ streaming->dev = dev;
streaming->intf = usb_get_intf(intf);
streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
@@ -589,12 +602,12 @@ static int uvc_parse_streaming(struct uvc_device *dev,
/* Parse the header descriptor. */
switch (buffer[2]) {
- case VS_OUTPUT_HEADER:
+ case UVC_VS_OUTPUT_HEADER:
streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
size = 9;
break;
- case VS_INPUT_HEADER:
+ case UVC_VS_INPUT_HEADER:
streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
size = 13;
break;
@@ -618,7 +631,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
streaming->header.bNumFormats = p;
streaming->header.bEndpointAddress = buffer[6];
- if (buffer[2] == VS_INPUT_HEADER) {
+ if (buffer[2] == UVC_VS_INPUT_HEADER) {
streaming->header.bmInfo = buffer[7];
streaming->header.bTerminalLink = buffer[8];
streaming->header.bStillCaptureMethod = buffer[9];
@@ -644,15 +657,15 @@ static int uvc_parse_streaming(struct uvc_device *dev,
_buflen = buflen;
/* Count the format and frame descriptors. */
- while (_buflen > 2 && _buffer[1] == CS_INTERFACE) {
+ while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {
switch (_buffer[2]) {
- case VS_FORMAT_UNCOMPRESSED:
- case VS_FORMAT_MJPEG:
- case VS_FORMAT_FRAME_BASED:
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_FRAME_BASED:
nformats++;
break;
- case VS_FORMAT_DV:
+ case UVC_VS_FORMAT_DV:
/* DV format has no frame descriptor. We will create a
* dummy frame descriptor with a dummy frame interval.
*/
@@ -661,22 +674,22 @@ static int uvc_parse_streaming(struct uvc_device *dev,
nintervals++;
break;
- case VS_FORMAT_MPEG2TS:
- case VS_FORMAT_STREAM_BASED:
+ case UVC_VS_FORMAT_MPEG2TS:
+ case UVC_VS_FORMAT_STREAM_BASED:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT %u is not supported.\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber, _buffer[2]);
break;
- case VS_FRAME_UNCOMPRESSED:
- case VS_FRAME_MJPEG:
+ case UVC_VS_FRAME_UNCOMPRESSED:
+ case UVC_VS_FRAME_MJPEG:
nframes++;
if (_buflen > 25)
nintervals += _buffer[25] ? _buffer[25] : 3;
break;
- case VS_FRAME_FRAME_BASED:
+ case UVC_VS_FRAME_FRAME_BASED:
nframes++;
if (_buflen > 21)
nintervals += _buffer[21] ? _buffer[21] : 3;
@@ -709,12 +722,12 @@ static int uvc_parse_streaming(struct uvc_device *dev,
streaming->nformats = nformats;
/* Parse the format descriptors. */
- while (buflen > 2 && buffer[1] == CS_INTERFACE) {
+ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
switch (buffer[2]) {
- case VS_FORMAT_UNCOMPRESSED:
- case VS_FORMAT_MJPEG:
- case VS_FORMAT_DV:
- case VS_FORMAT_FRAME_BASED:
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_DV:
+ case UVC_VS_FORMAT_FRAME_BASED:
format->frame = frame;
ret = uvc_parse_format(dev, streaming, format,
&interval, buffer, buflen);
@@ -751,7 +764,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
streaming->maxpsize = psize;
}
- list_add_tail(&streaming->list, &dev->streaming);
+ list_add_tail(&streaming->list, &dev->streams);
return 0;
error:
@@ -819,7 +832,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
return -ENOMEM;
unit->id = buffer[3];
- unit->type = VC_EXTENSION_UNIT;
+ unit->type = UVC_VC_EXTENSION_UNIT;
memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
unit->extension.bNumControls = buffer[20];
unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
@@ -856,7 +869,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
__u16 type;
switch (buffer[2]) {
- case VC_HEADER:
+ case UVC_VC_HEADER:
n = buflen >= 12 ? buffer[11] : 0;
if (buflen < 12 || buflen < 12 + n) {
@@ -883,7 +896,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
}
break;
- case VC_INPUT_TERMINAL:
+ case UVC_VC_INPUT_TERMINAL:
if (buflen < 8) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d INPUT_TERMINAL error\n",
@@ -908,11 +921,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
p = 0;
len = 8;
- if (type == ITT_CAMERA) {
+ if (type == UVC_ITT_CAMERA) {
n = buflen >= 15 ? buffer[14] : 0;
len = 15;
- } else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+ } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
n = buflen >= 9 ? buffer[8] : 0;
p = buflen >= 10 + n ? buffer[9+n] : 0;
len = 10;
@@ -932,7 +945,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
term->id = buffer[3];
term->type = type | UVC_TERM_INPUT;
- if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {
+ if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
term->camera.bControlSize = n;
term->camera.bmControls = (__u8 *)term + sizeof *term;
term->camera.wObjectiveFocalLengthMin =
@@ -942,7 +955,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
term->camera.wOcularFocalLength =
get_unaligned_le16(&buffer[12]);
memcpy(term->camera.bmControls, &buffer[15], n);
- } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
+ } else if (UVC_ENTITY_TYPE(term) ==
+ UVC_ITT_MEDIA_TRANSPORT_INPUT) {
term->media.bControlSize = n;
term->media.bmControls = (__u8 *)term + sizeof *term;
term->media.bTransportModeSize = p;
@@ -955,9 +969,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
if (buffer[7] != 0)
usb_string(udev, buffer[7], term->name,
sizeof term->name);
- else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)
+ else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
sprintf(term->name, "Camera %u", buffer[3]);
- else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)
+ else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
sprintf(term->name, "Media %u", buffer[3]);
else
sprintf(term->name, "Input %u", buffer[3]);
@@ -965,7 +979,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&term->list, &dev->entities);
break;
- case VC_OUTPUT_TERMINAL:
+ case UVC_VC_OUTPUT_TERMINAL:
if (buflen < 9) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d OUTPUT_TERMINAL error\n",
@@ -1002,7 +1016,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&term->list, &dev->entities);
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
p = buflen >= 5 ? buffer[4] : 0;
if (buflen < 5 || buflen < 6 + p) {
@@ -1031,7 +1045,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&unit->list, &dev->entities);
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
n = buflen >= 8 ? buffer[7] : 0;
p = dev->uvc_version >= 0x0110 ? 10 : 9;
@@ -1066,7 +1080,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&unit->list, &dev->entities);
break;
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
p = buflen >= 22 ? buffer[21] : 0;
n = buflen >= 24 + p ? buffer[22+p] : 0;
@@ -1158,43 +1172,40 @@ next_descriptor:
}
/* ------------------------------------------------------------------------
- * USB probe and disconnect
+ * UVC device scan
*/
/*
- * Unregister the video devices.
- */
-static void uvc_unregister_video(struct uvc_device *dev)
-{
- if (dev->video.vdev) {
- if (dev->video.vdev->minor == -1)
- video_device_release(dev->video.vdev);
- else
- video_unregister_device(dev->video.vdev);
- dev->video.vdev = NULL;
- }
-}
-
-/*
* Scan the UVC descriptors to locate a chain starting at an Output Terminal
* and containing the following units:
*
- * - one Output Terminal (USB Streaming or Display)
+ * - one or more Output Terminals (USB Streaming or Display)
* - zero or one Processing Unit
- * - zero, one or mode single-input Selector Units
+ * - zero, one or more single-input Selector Units
* - zero or one multiple-input Selector Units, provided all inputs are
* connected to input terminals
* - zero, one or mode single-input Extension Units
* - one or more Input Terminals (Camera, External or USB Streaming)
*
- * A side forward scan is made on each detected entity to check for additional
- * extension units.
+ * The terminal and units must match on of the following structures:
+ *
+ * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0)
+ * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ...
+ * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n)
+ *
+ * +---------+ +---------+ -> OTT_*(0)
+ * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ...
+ * +---------+ +---------+ -> OTT_*(n)
+ *
+ * The Processing Unit and Extension Units can be in any order. Additional
+ * Extension Units connected to the main chain as single-unit branches are
+ * also supported. Single-input Selector Units are ignored.
*/
-static int uvc_scan_chain_entity(struct uvc_video_device *video,
+static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
struct uvc_entity *entity)
{
switch (UVC_ENTITY_TYPE(entity)) {
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- XU %d", entity->id);
@@ -1204,23 +1215,23 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
return -1;
}
- list_add_tail(&entity->chain, &video->extensions);
+ list_add_tail(&entity->chain, &chain->extensions);
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- PU %d", entity->id);
- if (video->processing != NULL) {
+ if (chain->processing != NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found multiple "
"Processing Units in chain.\n");
return -1;
}
- video->processing = entity;
+ chain->processing = entity;
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- SU %d", entity->id);
@@ -1228,25 +1239,25 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
if (entity->selector.bNrInPins == 1)
break;
- if (video->selector != NULL) {
+ if (chain->selector != NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
"Units in chain.\n");
return -1;
}
- video->selector = entity;
+ chain->selector = entity;
break;
- case ITT_VENDOR_SPECIFIC:
- case ITT_CAMERA:
- case ITT_MEDIA_TRANSPORT_INPUT:
+ case UVC_ITT_VENDOR_SPECIFIC:
+ case UVC_ITT_CAMERA:
+ case UVC_ITT_MEDIA_TRANSPORT_INPUT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
- list_add_tail(&entity->chain, &video->iterms);
+ list_add_tail(&entity->chain, &chain->iterms);
break;
- case TT_STREAMING:
+ case UVC_TT_STREAMING:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
@@ -1256,14 +1267,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
return -1;
}
- if (video->sterm != NULL) {
- uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming "
- "entities in chain.\n");
- return -1;
- }
-
- list_add_tail(&entity->chain, &video->iterms);
- video->sterm = entity;
+ list_add_tail(&entity->chain, &chain->iterms);
break;
default:
@@ -1275,7 +1279,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
return 0;
}
-static int uvc_scan_chain_forward(struct uvc_video_device *video,
+static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
struct uvc_entity *entity, struct uvc_entity *prev)
{
struct uvc_entity *forward;
@@ -1286,28 +1290,51 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
found = 0;
while (1) {
- forward = uvc_entity_by_reference(video->dev, entity->id,
+ forward = uvc_entity_by_reference(chain->dev, entity->id,
forward);
if (forward == NULL)
break;
-
- if (UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT ||
- forward == prev)
+ if (forward == prev)
continue;
- if (forward->extension.bNrInPins != 1) {
- uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has "
- "more than 1 input pin.\n", entity->id);
- return -1;
- }
+ switch (UVC_ENTITY_TYPE(forward)) {
+ case UVC_VC_EXTENSION_UNIT:
+ if (forward->extension.bNrInPins != 1) {
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d "
+ "has more than 1 input pin.\n",
+ entity->id);
+ return -EINVAL;
+ }
+
+ list_add_tail(&forward->chain, &chain->extensions);
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ if (!found)
+ printk(" (->");
- list_add_tail(&forward->chain, &video->extensions);
- if (uvc_trace_param & UVC_TRACE_PROBE) {
- if (!found)
- printk(" (-> XU");
+ printk(" XU %d", forward->id);
+ found = 1;
+ }
+ break;
+
+ case UVC_OTT_VENDOR_SPECIFIC:
+ case UVC_OTT_DISPLAY:
+ case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+ case UVC_TT_STREAMING:
+ if (UVC_ENTITY_IS_ITERM(forward)) {
+ uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
+ "terminal %u.\n", forward->id);
+ return -EINVAL;
+ }
- printk(" %d", forward->id);
- found = 1;
+ list_add_tail(&forward->chain, &chain->oterms);
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ if (!found)
+ printk(" (->");
+
+ printk(" OT %d", forward->id);
+ found = 1;
+ }
+ break;
}
}
if (found)
@@ -1316,22 +1343,22 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
return 0;
}
-static int uvc_scan_chain_backward(struct uvc_video_device *video,
+static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
struct uvc_entity *entity)
{
struct uvc_entity *term;
int id = -1, i;
switch (UVC_ENTITY_TYPE(entity)) {
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
id = entity->extension.baSourceID[0];
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
id = entity->processing.bSourceID;
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
/* Single-input selector units are ignored. */
if (entity->selector.bNrInPins == 1) {
id = entity->selector.baSourceID[0];
@@ -1341,10 +1368,10 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video,
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT");
- video->selector = entity;
+ chain->selector = entity;
for (i = 0; i < entity->selector.bNrInPins; ++i) {
id = entity->selector.baSourceID[i];
- term = uvc_entity_by_id(video->dev, id);
+ term = uvc_entity_by_id(chain->dev, id);
if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
"input %d isn't connected to an "
@@ -1355,8 +1382,8 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video,
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" %d", term->id);
- list_add_tail(&term->chain, &video->iterms);
- uvc_scan_chain_forward(video, term, entity);
+ list_add_tail(&term->chain, &chain->iterms);
+ uvc_scan_chain_forward(chain, term, entity);
}
if (uvc_trace_param & UVC_TRACE_PROBE)
@@ -1369,125 +1396,170 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video,
return id;
}
-static int uvc_scan_chain(struct uvc_video_device *video)
+static int uvc_scan_chain(struct uvc_video_chain *chain,
+ struct uvc_entity *oterm)
{
struct uvc_entity *entity, *prev;
int id;
- entity = video->oterm;
+ entity = oterm;
+ list_add_tail(&entity->chain, &chain->oterms);
uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
- if (UVC_ENTITY_TYPE(entity) == TT_STREAMING)
- video->sterm = entity;
-
id = entity->output.bSourceID;
while (id != 0) {
prev = entity;
- entity = uvc_entity_by_id(video->dev, id);
+ entity = uvc_entity_by_id(chain->dev, id);
if (entity == NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found reference to "
"unknown entity %d.\n", id);
- return -1;
+ return -EINVAL;
+ }
+
+ if (entity->chain.next || entity->chain.prev) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+ "entity %d already in chain.\n", id);
+ return -EINVAL;
}
/* Process entity */
- if (uvc_scan_chain_entity(video, entity) < 0)
- return -1;
+ if (uvc_scan_chain_entity(chain, entity) < 0)
+ return -EINVAL;
/* Forward scan */
- if (uvc_scan_chain_forward(video, entity, prev) < 0)
- return -1;
+ if (uvc_scan_chain_forward(chain, entity, prev) < 0)
+ return -EINVAL;
/* Stop when a terminal is found. */
- if (!UVC_ENTITY_IS_UNIT(entity))
+ if (UVC_ENTITY_IS_TERM(entity))
break;
/* Backward scan */
- id = uvc_scan_chain_backward(video, entity);
+ id = uvc_scan_chain_backward(chain, entity);
if (id < 0)
return id;
}
- if (video->sterm == NULL) {
- uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in "
- "chain.\n");
- return -1;
+ return 0;
+}
+
+static unsigned int uvc_print_terms(struct list_head *terms, char *buffer)
+{
+ struct uvc_entity *term;
+ unsigned int nterms = 0;
+ char *p = buffer;
+
+ list_for_each_entry(term, terms, chain) {
+ p += sprintf(p, "%u", term->id);
+ if (term->chain.next != terms) {
+ p += sprintf(p, ",");
+ if (++nterms >= 4) {
+ p += sprintf(p, "...");
+ break;
+ }
+ }
}
- return 0;
+ return p - buffer;
+}
+
+static const char *uvc_print_chain(struct uvc_video_chain *chain)
+{
+ static char buffer[43];
+ char *p = buffer;
+
+ p += uvc_print_terms(&chain->iterms, p);
+ p += sprintf(p, " -> ");
+ uvc_print_terms(&chain->oterms, p);
+
+ return buffer;
}
/*
- * Register the video devices.
- *
- * The driver currently supports a single video device per control interface
- * only. The terminal and units must match the following structure:
+ * Scan the device for video chains and register video devices.
*
- * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
- * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_*
- *
- * The Extension Units, if present, must have a single input pin. The
- * Processing Unit and Extension Units can be in any order. Additional
- * Extension Units connected to the main chain as single-unit branches are
- * also supported.
+ * Chains are scanned starting at their output terminals and walked backwards.
*/
-static int uvc_register_video(struct uvc_device *dev)
+static int uvc_scan_device(struct uvc_device *dev)
{
- struct video_device *vdev;
+ struct uvc_video_chain *chain;
struct uvc_entity *term;
- int found = 0, ret;
- /* Check if the control interface matches the structure we expect. */
list_for_each_entry(term, &dev->entities, list) {
- struct uvc_streaming *streaming;
-
- if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term))
+ if (!UVC_ENTITY_IS_OTERM(term))
continue;
- memset(&dev->video, 0, sizeof dev->video);
- mutex_init(&dev->video.ctrl_mutex);
- INIT_LIST_HEAD(&dev->video.iterms);
- INIT_LIST_HEAD(&dev->video.extensions);
- dev->video.oterm = term;
- dev->video.dev = dev;
- if (uvc_scan_chain(&dev->video) < 0)
+ /* If the terminal is already included in a chain, skip it.
+ * This can happen for chains that have multiple output
+ * terminals, where all output terminals beside the first one
+ * will be inserted in the chain in forward scans.
+ */
+ if (term->chain.next || term->chain.prev)
continue;
- list_for_each_entry(streaming, &dev->streaming, list) {
- if (streaming->header.bTerminalLink ==
- dev->video.sterm->id) {
- dev->video.streaming = streaming;
- found = 1;
- break;
- }
+ chain = kzalloc(sizeof(*chain), GFP_KERNEL);
+ if (chain == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&chain->iterms);
+ INIT_LIST_HEAD(&chain->oterms);
+ INIT_LIST_HEAD(&chain->extensions);
+ mutex_init(&chain->ctrl_mutex);
+ chain->dev = dev;
+
+ if (uvc_scan_chain(chain, term) < 0) {
+ kfree(chain);
+ continue;
}
- if (found)
- break;
+ uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",
+ uvc_print_chain(chain));
+
+ list_add_tail(&chain->list, &dev->chains);
}
- if (!found) {
+ if (list_empty(&dev->chains)) {
uvc_printk(KERN_INFO, "No valid video chain found.\n");
return -1;
}
- if (uvc_trace_param & UVC_TRACE_PROBE) {
- uvc_printk(KERN_INFO, "Found a valid video chain (");
- list_for_each_entry(term, &dev->video.iterms, chain) {
- printk("%d", term->id);
- if (term->chain.next != &dev->video.iterms)
- printk(",");
- }
- printk(" -> %d).\n", dev->video.oterm->id);
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device registration and unregistration
+ */
+
+/*
+ * Unregister the video devices.
+ */
+static void uvc_unregister_video(struct uvc_device *dev)
+{
+ struct uvc_streaming *stream;
+
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->vdev == NULL)
+ continue;
+
+ if (stream->vdev->minor == -1)
+ video_device_release(stream->vdev);
+ else
+ video_unregister_device(stream->vdev);
+ stream->vdev = NULL;
}
+}
- /* Initialize the video buffers queue. */
- uvc_queue_init(&dev->video.queue, dev->video.streaming->type);
+static int uvc_register_video(struct uvc_device *dev,
+ struct uvc_streaming *stream)
+{
+ struct video_device *vdev;
+ int ret;
/* Initialize the streaming interface with default streaming
* parameters.
*/
- if ((ret = uvc_video_init(&dev->video)) < 0) {
+ ret = uvc_video_init(stream);
+ if (ret < 0) {
uvc_printk(KERN_ERR, "Failed to initialize the device "
"(%d).\n", ret);
return ret;
@@ -1495,8 +1567,11 @@ static int uvc_register_video(struct uvc_device *dev)
/* Register the device with V4L. */
vdev = video_device_alloc();
- if (vdev == NULL)
- return -1;
+ if (vdev == NULL) {
+ uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n",
+ ret);
+ return -ENOMEM;
+ }
/* We already hold a reference to dev->udev. The video device will be
* unregistered before the reference is released, so we don't need to
@@ -1511,19 +1586,74 @@ static int uvc_register_video(struct uvc_device *dev)
/* Set the driver data before calling video_register_device, otherwise
* uvc_v4l2_open might race us.
*/
- dev->video.vdev = vdev;
- video_set_drvdata(vdev, &dev->video);
-
- if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
- dev->video.vdev = NULL;
+ stream->vdev = vdev;
+ video_set_drvdata(vdev, stream);
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ uvc_printk(KERN_ERR, "Failed to register video device (%d).\n",
+ ret);
+ stream->vdev = NULL;
video_device_release(vdev);
- return -1;
+ return ret;
}
return 0;
}
/*
+ * Register all video devices in all chains.
+ */
+static int uvc_register_terms(struct uvc_device *dev,
+ struct uvc_video_chain *chain, struct list_head *terms)
+{
+ struct uvc_streaming *stream;
+ struct uvc_entity *term;
+ int ret;
+
+ list_for_each_entry(term, terms, chain) {
+ if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
+ continue;
+
+ stream = uvc_stream_by_id(dev, term->id);
+ if (stream == NULL) {
+ uvc_printk(KERN_INFO, "No streaming interface found "
+ "for terminal %u.", term->id);
+ continue;
+ }
+
+ stream->chain = chain;
+ ret = uvc_register_video(dev, stream);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int uvc_register_chains(struct uvc_device *dev)
+{
+ struct uvc_video_chain *chain;
+ int ret;
+
+ list_for_each_entry(chain, &dev->chains, list) {
+ ret = uvc_register_terms(dev, chain, &chain->iterms);
+ if (ret < 0)
+ return ret;
+
+ ret = uvc_register_terms(dev, chain, &chain->oterms);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * USB probe, disconnect, suspend and resume
+ */
+
+/*
* Delete the UVC device.
*
* Called by the kernel when the last reference to the uvc_device structure
@@ -1544,7 +1674,7 @@ void uvc_delete(struct kref *kref)
struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
struct list_head *p, *n;
- /* Unregister the video device. */
+ /* Unregister the video devices. */
uvc_unregister_video(dev);
usb_put_intf(dev->intf);
usb_put_dev(dev->udev);
@@ -1552,13 +1682,19 @@ void uvc_delete(struct kref *kref)
uvc_status_cleanup(dev);
uvc_ctrl_cleanup_device(dev);
+ list_for_each_safe(p, n, &dev->chains) {
+ struct uvc_video_chain *chain;
+ chain = list_entry(p, struct uvc_video_chain, list);
+ kfree(chain);
+ }
+
list_for_each_safe(p, n, &dev->entities) {
struct uvc_entity *entity;
entity = list_entry(p, struct uvc_entity, list);
kfree(entity);
}
- list_for_each_safe(p, n, &dev->streaming) {
+ list_for_each_safe(p, n, &dev->streams) {
struct uvc_streaming *streaming;
streaming = list_entry(p, struct uvc_streaming, list);
usb_driver_release_interface(&uvc_driver.driver,
@@ -1592,7 +1728,8 @@ static int uvc_probe(struct usb_interface *intf,
return -ENOMEM;
INIT_LIST_HEAD(&dev->entities);
- INIT_LIST_HEAD(&dev->streaming);
+ INIT_LIST_HEAD(&dev->chains);
+ INIT_LIST_HEAD(&dev->streams);
kref_init(&dev->kref);
atomic_set(&dev->users, 0);
@@ -1633,8 +1770,12 @@ static int uvc_probe(struct usb_interface *intf,
if (uvc_ctrl_init_device(dev) < 0)
goto error;
- /* Register the video devices. */
- if (uvc_register_video(dev) < 0)
+ /* Scan the device for video chains. */
+ if (uvc_scan_device(dev) < 0)
+ goto error;
+
+ /* Register video devices. */
+ if (uvc_register_chains(dev) < 0)
goto error;
/* Save our data pointer in the interface data. */
@@ -1664,7 +1805,8 @@ static void uvc_disconnect(struct usb_interface *intf)
*/
usb_set_intfdata(intf, NULL);
- if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOSTREAMING)
return;
/* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
@@ -1687,31 +1829,36 @@ static void uvc_disconnect(struct usb_interface *intf)
static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
{
struct uvc_device *dev = usb_get_intfdata(intf);
+ struct uvc_streaming *stream;
uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
intf->cur_altsetting->desc.bInterfaceNumber);
/* Controls are cached on the fly so they don't need to be saved. */
- if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOCONTROL)
return uvc_status_suspend(dev);
- if (dev->video.streaming->intf != intf) {
- uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB "
- "interface mismatch.\n");
- return -EINVAL;
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->intf == intf)
+ return uvc_video_suspend(stream);
}
- return uvc_video_suspend(&dev->video);
+ uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
+ "mismatch.\n");
+ return -EINVAL;
}
static int __uvc_resume(struct usb_interface *intf, int reset)
{
struct uvc_device *dev = usb_get_intfdata(intf);
+ struct uvc_streaming *stream;
uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
intf->cur_altsetting->desc.bInterfaceNumber);
- if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOCONTROL) {
if (reset) {
int ret = uvc_ctrl_resume_device(dev);
@@ -1722,13 +1869,14 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
return uvc_status_resume(dev);
}
- if (dev->video.streaming->intf != intf) {
- uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB "
- "interface mismatch.\n");
- return -EINVAL;
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->intf == intf)
+ return uvc_video_resume(stream);
}
- return uvc_video_resume(&dev->video);
+ uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
+ "mismatch.\n");
+ return -EINVAL;
}
static int uvc_resume(struct usb_interface *intf)
@@ -1880,7 +2028,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_PROBE_DEF },
/* Syntek (HP Spartan) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1943,7 +2092,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_PROBE_EXTRAFIELDS },
/* Ecamm Pico iMage */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
index 436f462685a0..a9285b570dbe 100644
--- a/drivers/media/video/uvc/uvc_isight.c
+++ b/drivers/media/video/uvc/uvc_isight.c
@@ -99,7 +99,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
return 0;
}
-void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
struct uvc_buffer *buf)
{
int ret, i;
@@ -120,7 +120,7 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
* processes the data of the first payload of the new frame.
*/
do {
- ret = isight_decode(&video->queue, buf,
+ ret = isight_decode(&stream->queue, buf,
urb->transfer_buffer +
urb->iso_frame_desc[i].offset,
urb->iso_frame_desc[i].actual_length);
@@ -130,7 +130,8 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
if (buf->state == UVC_BUF_STATE_DONE ||
buf->state == UVC_BUF_STATE_ERROR)
- buf = uvc_queue_next_buffer(&video->queue, buf);
+ buf = uvc_queue_next_buffer(&stream->queue,
+ buf);
} while (ret == -EAGAIN);
}
}
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 5e77cad29690..9e7351569b5d 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -40,7 +40,7 @@
* table for the controls that can be mapped directly, and handle the others
* manually.
*/
-static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu)
{
struct uvc_menu_info *menu_info;
@@ -49,7 +49,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
u32 index = query_menu->index;
u32 id = query_menu->id;
- ctrl = uvc_find_control(video, query_menu->id, &mapping);
+ ctrl = uvc_find_control(chain, query_menu->id, &mapping);
if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
return -EINVAL;
@@ -103,7 +103,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
return interval;
}
-static int uvc_v4l2_try_format(struct uvc_video_device *video,
+static int uvc_v4l2_try_format(struct uvc_streaming *stream,
struct v4l2_format *fmt, struct uvc_streaming_control *probe,
struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
{
@@ -116,7 +116,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
int ret = 0;
__u8 *fcc;
- if (fmt->type != video->streaming->type)
+ if (fmt->type != stream->type)
return -EINVAL;
fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@@ -126,8 +126,8 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
fmt->fmt.pix.width, fmt->fmt.pix.height);
/* Check if the hardware supports the requested format. */
- for (i = 0; i < video->streaming->nformats; ++i) {
- format = &video->streaming->format[i];
+ for (i = 0; i < stream->nformats; ++i) {
+ format = &stream->format[i];
if (format->fcc == fmt->fmt.pix.pixelformat)
break;
}
@@ -191,12 +191,13 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
* developers test their webcams with the Linux driver as well as with
* the Windows driver).
*/
- if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+ if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize =
- video->streaming->ctrl.dwMaxVideoFrameSize;
+ stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */
- if ((ret = uvc_probe_video(video, probe)) < 0)
+ ret = uvc_probe_video(stream, probe);
+ if (ret < 0)
goto done;
fmt->fmt.pix.width = frame->wWidth;
@@ -216,13 +217,13 @@ done:
return ret;
}
-static int uvc_v4l2_get_format(struct uvc_video_device *video,
+static int uvc_v4l2_get_format(struct uvc_streaming *stream,
struct v4l2_format *fmt)
{
- struct uvc_format *format = video->streaming->cur_format;
- struct uvc_frame *frame = video->streaming->cur_frame;
+ struct uvc_format *format = stream->cur_format;
+ struct uvc_frame *frame = stream->cur_frame;
- if (fmt->type != video->streaming->type)
+ if (fmt->type != stream->type)
return -EINVAL;
if (format == NULL || frame == NULL)
@@ -233,14 +234,14 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video,
fmt->fmt.pix.height = frame->wHeight;
fmt->fmt.pix.field = V4L2_FIELD_NONE;
fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
- fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize;
+ fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize;
fmt->fmt.pix.colorspace = format->colorspace;
fmt->fmt.pix.priv = 0;
return 0;
}
-static int uvc_v4l2_set_format(struct uvc_video_device *video,
+static int uvc_v4l2_set_format(struct uvc_streaming *stream,
struct v4l2_format *fmt)
{
struct uvc_streaming_control probe;
@@ -248,39 +249,39 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
struct uvc_frame *frame;
int ret;
- if (fmt->type != video->streaming->type)
+ if (fmt->type != stream->type)
return -EINVAL;
- if (uvc_queue_allocated(&video->queue))
+ if (uvc_queue_allocated(&stream->queue))
return -EBUSY;
- ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
+ ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
if (ret < 0)
return ret;
- memcpy(&video->streaming->ctrl, &probe, sizeof probe);
- video->streaming->cur_format = format;
- video->streaming->cur_frame = frame;
+ memcpy(&stream->ctrl, &probe, sizeof probe);
+ stream->cur_format = format;
+ stream->cur_frame = frame;
return 0;
}
-static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
+static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm)
{
uint32_t numerator, denominator;
- if (parm->type != video->streaming->type)
+ if (parm->type != stream->type)
return -EINVAL;
- numerator = video->streaming->ctrl.dwFrameInterval;
+ numerator = stream->ctrl.dwFrameInterval;
denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
memset(parm, 0, sizeof *parm);
- parm->type = video->streaming->type;
+ parm->type = stream->type;
- if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
parm->parm.capture.capturemode = 0;
parm->parm.capture.timeperframe.numerator = numerator;
@@ -297,19 +298,19 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
return 0;
}
-static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
+static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm)
{
- struct uvc_frame *frame = video->streaming->cur_frame;
+ struct uvc_frame *frame = stream->cur_frame;
struct uvc_streaming_control probe;
struct v4l2_fract timeperframe;
uint32_t interval;
int ret;
- if (parm->type != video->streaming->type)
+ if (parm->type != stream->type)
return -EINVAL;
- if (uvc_queue_streaming(&video->queue))
+ if (uvc_queue_streaming(&stream->queue))
return -EBUSY;
if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -317,7 +318,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
else
timeperframe = parm->parm.output.timeperframe;
- memcpy(&probe, &video->streaming->ctrl, sizeof probe);
+ memcpy(&probe, &stream->ctrl, sizeof probe);
interval = uvc_fraction_to_interval(timeperframe.numerator,
timeperframe.denominator);
@@ -326,10 +327,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
/* Probe the device with the new settings. */
- if ((ret = uvc_probe_video(video, &probe)) < 0)
+ ret = uvc_probe_video(stream, &probe);
+ if (ret < 0)
return ret;
- memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+ memcpy(&stream->ctrl, &probe, sizeof probe);
/* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval;
@@ -382,8 +384,8 @@ static int uvc_acquire_privileges(struct uvc_fh *handle)
/* Check if the device already has a privileged handle. */
mutex_lock(&uvc_driver.open_mutex);
- if (atomic_inc_return(&handle->device->active) != 1) {
- atomic_dec(&handle->device->active);
+ if (atomic_inc_return(&handle->stream->active) != 1) {
+ atomic_dec(&handle->stream->active);
ret = -EBUSY;
goto done;
}
@@ -398,7 +400,7 @@ done:
static void uvc_dismiss_privileges(struct uvc_fh *handle)
{
if (handle->state == UVC_HANDLE_ACTIVE)
- atomic_dec(&handle->device->active);
+ atomic_dec(&handle->stream->active);
handle->state = UVC_HANDLE_PASSIVE;
}
@@ -414,45 +416,47 @@ static int uvc_has_privileges(struct uvc_fh *handle)
static int uvc_v4l2_open(struct file *file)
{
- struct uvc_video_device *video;
+ struct uvc_streaming *stream;
struct uvc_fh *handle;
int ret = 0;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
mutex_lock(&uvc_driver.open_mutex);
- video = video_drvdata(file);
+ stream = video_drvdata(file);
- if (video->dev->state & UVC_DEV_DISCONNECTED) {
+ if (stream->dev->state & UVC_DEV_DISCONNECTED) {
ret = -ENODEV;
goto done;
}
- ret = usb_autopm_get_interface(video->dev->intf);
+ ret = usb_autopm_get_interface(stream->dev->intf);
if (ret < 0)
goto done;
/* Create the device handle. */
handle = kzalloc(sizeof *handle, GFP_KERNEL);
if (handle == NULL) {
- usb_autopm_put_interface(video->dev->intf);
+ usb_autopm_put_interface(stream->dev->intf);
ret = -ENOMEM;
goto done;
}
- if (atomic_inc_return(&video->dev->users) == 1) {
- if ((ret = uvc_status_start(video->dev)) < 0) {
- usb_autopm_put_interface(video->dev->intf);
- atomic_dec(&video->dev->users);
+ if (atomic_inc_return(&stream->dev->users) == 1) {
+ ret = uvc_status_start(stream->dev);
+ if (ret < 0) {
+ usb_autopm_put_interface(stream->dev->intf);
+ atomic_dec(&stream->dev->users);
kfree(handle);
goto done;
}
}
- handle->device = video;
+ handle->chain = stream->chain;
+ handle->stream = stream;
handle->state = UVC_HANDLE_PASSIVE;
file->private_data = handle;
- kref_get(&video->dev->kref);
+ kref_get(&stream->dev->kref);
done:
mutex_unlock(&uvc_driver.open_mutex);
@@ -461,20 +465,20 @@ done:
static int uvc_v4l2_release(struct file *file)
{
- struct uvc_video_device *video = video_drvdata(file);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
/* Only free resources if this is a privileged handle. */
if (uvc_has_privileges(handle)) {
- uvc_video_enable(video, 0);
+ uvc_video_enable(stream, 0);
- mutex_lock(&video->queue.mutex);
- if (uvc_free_buffers(&video->queue) < 0)
+ mutex_lock(&stream->queue.mutex);
+ if (uvc_free_buffers(&stream->queue) < 0)
uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
"free buffers.\n");
- mutex_unlock(&video->queue.mutex);
+ mutex_unlock(&stream->queue.mutex);
}
/* Release the file handle. */
@@ -482,19 +486,20 @@ static int uvc_v4l2_release(struct file *file)
kfree(handle);
file->private_data = NULL;
- if (atomic_dec_return(&video->dev->users) == 0)
- uvc_status_stop(video->dev);
+ if (atomic_dec_return(&stream->dev->users) == 0)
+ uvc_status_stop(stream->dev);
- usb_autopm_put_interface(video->dev->intf);
- kref_put(&video->dev->kref, uvc_delete);
+ usb_autopm_put_interface(stream->dev->intf);
+ kref_put(&stream->dev->kref, uvc_delete);
return 0;
}
static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
- struct uvc_video_device *video = video_get_drvdata(vdev);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_video_chain *chain = handle->chain;
+ struct uvc_streaming *stream = handle->stream;
long ret = 0;
switch (cmd) {
@@ -506,10 +511,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(cap, 0, sizeof *cap);
strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
strlcpy(cap->card, vdev->name, sizeof cap->card);
- usb_make_path(video->dev->udev,
+ usb_make_path(stream->dev->udev,
cap->bus_info, sizeof(cap->bus_info));
cap->version = DRIVER_VERSION_NUMBER;
- if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING;
else
@@ -520,7 +525,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Get, Set & Query control */
case VIDIOC_QUERYCTRL:
- return uvc_query_v4l2_ctrl(video, arg);
+ return uvc_query_v4l2_ctrl(chain, arg);
case VIDIOC_G_CTRL:
{
@@ -530,12 +535,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(&xctrl, 0, sizeof xctrl);
xctrl.id = ctrl->id;
- ret = uvc_ctrl_begin(video);
- if (ret < 0)
+ ret = uvc_ctrl_begin(chain);
+ if (ret < 0)
return ret;
- ret = uvc_ctrl_get(video, &xctrl);
- uvc_ctrl_rollback(video);
+ ret = uvc_ctrl_get(chain, &xctrl);
+ uvc_ctrl_rollback(chain);
if (ret >= 0)
ctrl->value = xctrl.value;
break;
@@ -550,21 +555,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
xctrl.id = ctrl->id;
xctrl.value = ctrl->value;
- ret = uvc_ctrl_begin(video);
- if (ret < 0)
+ uvc_ctrl_begin(chain);
+ if (ret < 0)
return ret;
- ret = uvc_ctrl_set(video, &xctrl);
+ ret = uvc_ctrl_set(chain, &xctrl);
if (ret < 0) {
- uvc_ctrl_rollback(video);
+ uvc_ctrl_rollback(chain);
return ret;
}
- ret = uvc_ctrl_commit(video);
+ ret = uvc_ctrl_commit(chain);
break;
}
case VIDIOC_QUERYMENU:
- return uvc_v4l2_query_menu(video, arg);
+ return uvc_v4l2_query_menu(chain, arg);
case VIDIOC_G_EXT_CTRLS:
{
@@ -572,20 +577,20 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i;
- ret = uvc_ctrl_begin(video);
- if (ret < 0)
+ ret = uvc_ctrl_begin(chain);
+ if (ret < 0)
return ret;
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_get(video, ctrl);
+ ret = uvc_ctrl_get(chain, ctrl);
if (ret < 0) {
- uvc_ctrl_rollback(video);
+ uvc_ctrl_rollback(chain);
ctrls->error_idx = i;
return ret;
}
}
ctrls->error_idx = 0;
- ret = uvc_ctrl_rollback(video);
+ ret = uvc_ctrl_rollback(chain);
break;
}
@@ -596,14 +601,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i;
- ret = uvc_ctrl_begin(video);
+ ret = uvc_ctrl_begin(chain);
if (ret < 0)
return ret;
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_set(video, ctrl);
+ ret = uvc_ctrl_set(chain, ctrl);
if (ret < 0) {
- uvc_ctrl_rollback(video);
+ uvc_ctrl_rollback(chain);
ctrls->error_idx = i;
return ret;
}
@@ -612,31 +617,31 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
ctrls->error_idx = 0;
if (cmd == VIDIOC_S_EXT_CTRLS)
- ret = uvc_ctrl_commit(video);
+ ret = uvc_ctrl_commit(chain);
else
- ret = uvc_ctrl_rollback(video);
+ ret = uvc_ctrl_rollback(chain);
break;
}
/* Get, Set & Enum input */
case VIDIOC_ENUMINPUT:
{
- const struct uvc_entity *selector = video->selector;
+ const struct uvc_entity *selector = chain->selector;
struct v4l2_input *input = arg;
struct uvc_entity *iterm = NULL;
u32 index = input->index;
int pin = 0;
if (selector == NULL ||
- (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
if (index != 0)
return -EINVAL;
- iterm = list_first_entry(&video->iterms,
+ iterm = list_first_entry(&chain->iterms,
struct uvc_entity, chain);
pin = iterm->id;
} else if (pin < selector->selector.bNrInPins) {
pin = selector->selector.baSourceID[index];
- list_for_each_entry(iterm, video->iterms.next, chain) {
+ list_for_each_entry(iterm, chain->iterms.next, chain) {
if (iterm->id == pin)
break;
}
@@ -648,7 +653,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(input, 0, sizeof *input);
input->index = index;
strlcpy(input->name, iterm->name, sizeof input->name);
- if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+ if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
input->type = V4L2_INPUT_TYPE_CAMERA;
break;
}
@@ -657,15 +662,15 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
u8 input;
- if (video->selector == NULL ||
- (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (chain->selector == NULL ||
+ (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
*(int *)arg = 0;
break;
}
- ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
- video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
- &input, 1);
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
+ chain->selector->id, chain->dev->intfnum,
+ UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
if (ret < 0)
return ret;
@@ -680,19 +685,19 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- if (video->selector == NULL ||
- (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (chain->selector == NULL ||
+ (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
if (input != 1)
return -EINVAL;
break;
}
- if (input == 0 || input > video->selector->selector.bNrInPins)
+ if (input == 0 || input > chain->selector->selector.bNrInPins)
return -EINVAL;
- return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
- video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
- &input, 1);
+ return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
+ chain->selector->id, chain->dev->intfnum,
+ UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
}
/* Try, Get, Set & Enum format */
@@ -703,15 +708,15 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
enum v4l2_buf_type type = fmt->type;
__u32 index = fmt->index;
- if (fmt->type != video->streaming->type ||
- fmt->index >= video->streaming->nformats)
+ if (fmt->type != stream->type ||
+ fmt->index >= stream->nformats)
return -EINVAL;
memset(fmt, 0, sizeof(*fmt));
fmt->index = index;
fmt->type = type;
- format = &video->streaming->format[fmt->index];
+ format = &stream->format[fmt->index];
fmt->flags = 0;
if (format->flags & UVC_FMT_FLAG_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@@ -729,17 +734,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
+ return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
}
case VIDIOC_S_FMT:
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- return uvc_v4l2_set_format(video, arg);
+ return uvc_v4l2_set_format(stream, arg);
case VIDIOC_G_FMT:
- return uvc_v4l2_get_format(video, arg);
+ return uvc_v4l2_get_format(stream, arg);
/* Frame size enumeration */
case VIDIOC_ENUM_FRAMESIZES:
@@ -750,10 +755,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
int i;
/* Look for the given pixel format */
- for (i = 0; i < video->streaming->nformats; i++) {
- if (video->streaming->format[i].fcc ==
+ for (i = 0; i < stream->nformats; i++) {
+ if (stream->format[i].fcc ==
fsize->pixel_format) {
- format = &video->streaming->format[i];
+ format = &stream->format[i];
break;
}
}
@@ -779,10 +784,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
int i;
/* Look for the given pixel format and frame size */
- for (i = 0; i < video->streaming->nformats; i++) {
- if (video->streaming->format[i].fcc ==
+ for (i = 0; i < stream->nformats; i++) {
+ if (stream->format[i].fcc ==
fival->pixel_format) {
- format = &video->streaming->format[i];
+ format = &stream->format[i];
break;
}
}
@@ -832,21 +837,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Get & Set streaming parameters */
case VIDIOC_G_PARM:
- return uvc_v4l2_get_streamparm(video, arg);
+ return uvc_v4l2_get_streamparm(stream, arg);
case VIDIOC_S_PARM:
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- return uvc_v4l2_set_streamparm(video, arg);
+ return uvc_v4l2_set_streamparm(stream, arg);
/* Cropping and scaling */
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *ccap = arg;
- struct uvc_frame *frame = video->streaming->cur_frame;
+ struct uvc_frame *frame = stream->cur_frame;
- if (ccap->type != video->streaming->type)
+ if (ccap->type != stream->type)
return -EINVAL;
ccap->bounds.left = 0;
@@ -870,16 +875,16 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_requestbuffers *rb = arg;
unsigned int bufsize =
- video->streaming->ctrl.dwMaxVideoFrameSize;
+ stream->ctrl.dwMaxVideoFrameSize;
- if (rb->type != video->streaming->type ||
+ if (rb->type != stream->type ||
rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+ ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
if (ret < 0)
return ret;
@@ -892,39 +897,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_buffer *buf = arg;
- if (buf->type != video->streaming->type)
+ if (buf->type != stream->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
return -EBUSY;
- return uvc_query_buffer(&video->queue, buf);
+ return uvc_query_buffer(&stream->queue, buf);
}
case VIDIOC_QBUF:
if (!uvc_has_privileges(handle))
return -EBUSY;
- return uvc_queue_buffer(&video->queue, arg);
+ return uvc_queue_buffer(&stream->queue, arg);
case VIDIOC_DQBUF:
if (!uvc_has_privileges(handle))
return -EBUSY;
- return uvc_dequeue_buffer(&video->queue, arg,
+ return uvc_dequeue_buffer(&stream->queue, arg,
file->f_flags & O_NONBLOCK);
case VIDIOC_STREAMON:
{
int *type = arg;
- if (*type != video->streaming->type)
+ if (*type != stream->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
return -EBUSY;
- if ((ret = uvc_video_enable(video, 1)) < 0)
+ ret = uvc_video_enable(stream, 1);
+ if (ret < 0)
return ret;
break;
}
@@ -933,13 +939,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
int *type = arg;
- if (*type != video->streaming->type)
+ if (*type != stream->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
return -EBUSY;
- return uvc_video_enable(video, 0);
+ return uvc_video_enable(stream, 0);
}
/* Analog video standards make no sense for digital cameras. */
@@ -1013,10 +1019,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
case UVCIOC_CTRL_GET:
- return uvc_xu_ctrl_query(video, arg, 0);
+ return uvc_xu_ctrl_query(chain, arg, 0);
case UVCIOC_CTRL_SET:
- return uvc_xu_ctrl_query(video, arg, 1);
+ return uvc_xu_ctrl_query(chain, arg, 1);
default:
if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
@@ -1070,7 +1076,9 @@ static struct vm_operations_struct uvc_vm_ops = {
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct uvc_video_device *video = video_drvdata(file);
+ struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_streaming *stream = handle->stream;
+ struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *uninitialized_var(buffer);
struct page *page;
unsigned long addr, start, size;
@@ -1082,15 +1090,15 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
start = vma->vm_start;
size = vma->vm_end - vma->vm_start;
- mutex_lock(&video->queue.mutex);
+ mutex_lock(&queue->mutex);
- for (i = 0; i < video->queue.count; ++i) {
- buffer = &video->queue.buffer[i];
+ for (i = 0; i < queue->count; ++i) {
+ buffer = &queue->buffer[i];
if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
break;
}
- if (i == video->queue.count || size != video->queue.buf_size) {
+ if (i == queue->count || size != queue->buf_size) {
ret = -EINVAL;
goto done;
}
@@ -1101,7 +1109,7 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
*/
vma->vm_flags |= VM_IO;
- addr = (unsigned long)video->queue.mem + buffer->buf.m.offset;
+ addr = (unsigned long)queue->mem + buffer->buf.m.offset;
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -1117,17 +1125,18 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
uvc_vm_open(vma);
done:
- mutex_unlock(&video->queue.mutex);
+ mutex_unlock(&queue->mutex);
return ret;
}
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
{
- struct uvc_video_device *video = video_drvdata(file);
+ struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
- return uvc_queue_poll(&video->queue, file, wait);
+ return uvc_queue_poll(&stream->queue, file, wait);
}
const struct v4l2_file_operations uvc_fops = {
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 01b633c73480..5b757f32d997 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
return 0;
}
-static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
+static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl)
{
struct uvc_format *format;
@@ -69,10 +69,10 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
unsigned int i;
if (ctrl->bFormatIndex <= 0 ||
- ctrl->bFormatIndex > video->streaming->nformats)
+ ctrl->bFormatIndex > stream->nformats)
return;
- format = &video->streaming->format[ctrl->bFormatIndex - 1];
+ format = &stream->format[ctrl->bFormatIndex - 1];
for (i = 0; i < format->nframes; ++i) {
if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
@@ -86,12 +86,12 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
(ctrl->dwMaxVideoFrameSize == 0 &&
- video->dev->uvc_version < 0x0110))
+ stream->dev->uvc_version < 0x0110))
ctrl->dwMaxVideoFrameSize =
frame->dwMaxVideoFrameBufferSize;
- if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
- video->streaming->intf->num_altsetting > 1) {
+ if (stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
+ stream->intf->num_altsetting > 1) {
u32 interval;
u32 bandwidth;
@@ -108,7 +108,7 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
bandwidth *= 10000000 / interval + 1;
bandwidth /= 1000;
- if (video->dev->udev->speed == USB_SPEED_HIGH)
+ if (stream->dev->udev->speed == USB_SPEED_HIGH)
bandwidth /= 8;
bandwidth += 12;
@@ -116,40 +116,43 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
}
}
-static int uvc_get_video_ctrl(struct uvc_video_device *video,
+static int uvc_get_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl, int probe, __u8 query)
{
__u8 *data;
__u16 size;
int ret;
- size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+ size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
data = kmalloc(size, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
- ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
- probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
- UVC_CTRL_STREAMING_TIMEOUT);
+ if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF)
+ return -EIO;
+
+ ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
+ probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+ size, UVC_CTRL_STREAMING_TIMEOUT);
- if ((query == GET_MIN || query == GET_MAX) && ret == 2) {
+ if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
/* Some cameras, mostly based on Bison Electronics chipsets,
* answer a GET_MIN or GET_MAX request with the wCompQuality
* field only.
*/
- uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non "
+ uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non "
"compliance - GET_MIN/MAX(PROBE) incorrectly "
"supported. Enabling workaround.\n");
memset(ctrl, 0, sizeof ctrl);
ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
ret = 0;
goto out;
- } else if (query == GET_DEF && probe == 1 && ret != size) {
+ } else if (query == UVC_GET_DEF && probe == 1 && ret != size) {
/* Many cameras don't support the GET_DEF request on their
* video probe control. Warn once and return, the caller will
* fall back to GET_CUR.
*/
- uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non "
+ uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non "
"compliance - GET_DEF(PROBE) not supported. "
"Enabling workaround.\n");
ret = -EIO;
@@ -181,7 +184,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
ctrl->bMinVersion = data[32];
ctrl->bMaxVersion = data[33];
} else {
- ctrl->dwClockFrequency = video->dev->clock_frequency;
+ ctrl->dwClockFrequency = stream->dev->clock_frequency;
ctrl->bmFramingInfo = 0;
ctrl->bPreferedVersion = 0;
ctrl->bMinVersion = 0;
@@ -192,7 +195,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
* dwMaxPayloadTransferSize fields. Try to get the value from the
* format and frame descriptors.
*/
- uvc_fixup_video_ctrl(video, ctrl);
+ uvc_fixup_video_ctrl(stream, ctrl);
ret = 0;
out:
@@ -200,14 +203,14 @@ out:
return ret;
}
-static int uvc_set_video_ctrl(struct uvc_video_device *video,
+static int uvc_set_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl, int probe)
{
__u8 *data;
__u16 size;
int ret;
- size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+ size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
data = kzalloc(size, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
@@ -232,10 +235,9 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video,
data[33] = ctrl->bMaxVersion;
}
- ret = __uvc_query_ctrl(video->dev, SET_CUR, 0,
- video->streaming->intfnum,
- probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
- UVC_CTRL_STREAMING_TIMEOUT);
+ ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
+ probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+ size, UVC_CTRL_STREAMING_TIMEOUT);
if (ret != size) {
uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
"%d (exp. %u).\n", probe ? "probe" : "commit",
@@ -247,7 +249,7 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video,
return ret;
}
-int uvc_probe_video(struct uvc_video_device *video,
+int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe)
{
struct uvc_streaming_control probe_min, probe_max;
@@ -255,7 +257,7 @@ int uvc_probe_video(struct uvc_video_device *video,
unsigned int i;
int ret;
- mutex_lock(&video->streaming->mutex);
+ mutex_lock(&stream->mutex);
/* Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the
@@ -264,15 +266,16 @@ int uvc_probe_video(struct uvc_video_device *video,
* that reason, if the needed bandwidth exceeds the maximum available
* bandwidth, try to lower the quality.
*/
- if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0)
+ ret = uvc_set_video_ctrl(stream, probe, 1);
+ if (ret < 0)
goto done;
/* Get the minimum and maximum values for compression settings. */
- if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
- ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN);
+ if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
+ ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN);
if (ret < 0)
goto done;
- ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX);
+ ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX);
if (ret < 0)
goto done;
@@ -280,18 +283,21 @@ int uvc_probe_video(struct uvc_video_device *video,
}
for (i = 0; i < 2; ++i) {
- if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0 ||
- (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ ret = uvc_set_video_ctrl(stream, probe, 1);
+ if (ret < 0)
+ goto done;
+ ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
+ if (ret < 0)
goto done;
- if (video->streaming->intf->num_altsetting == 1)
+ if (stream->intf->num_altsetting == 1)
break;
bandwidth = probe->dwMaxPayloadTransferSize;
- if (bandwidth <= video->streaming->maxpsize)
+ if (bandwidth <= stream->maxpsize)
break;
- if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
+ if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
ret = -ENOSPC;
goto done;
}
@@ -304,14 +310,14 @@ int uvc_probe_video(struct uvc_video_device *video,
}
done:
- mutex_unlock(&video->streaming->mutex);
+ mutex_unlock(&stream->mutex);
return ret;
}
-int uvc_commit_video(struct uvc_video_device *video,
+int uvc_commit_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe)
{
- return uvc_set_video_ctrl(video, probe, 0);
+ return uvc_set_video_ctrl(stream, probe, 0);
}
/* ------------------------------------------------------------------------
@@ -363,7 +369,7 @@ int uvc_commit_video(struct uvc_video_device *video,
* to be called with a NULL buf parameter. uvc_video_decode_data and
* uvc_video_decode_end will never be called with a NULL buffer.
*/
-static int uvc_video_decode_start(struct uvc_video_device *video,
+static int uvc_video_decode_start(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len)
{
__u8 fid;
@@ -389,25 +395,25 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* NULL.
*/
if (buf == NULL) {
- video->last_fid = fid;
+ stream->last_fid = fid;
return -ENODATA;
}
/* Synchronize to the input stream by waiting for the FID bit to be
* toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
- * video->last_fid is initialized to -1, so the first isochronous
+ * stream->last_fid is initialized to -1, so the first isochronous
* frame will always be in sync.
*
- * If the device doesn't toggle the FID bit, invert video->last_fid
+ * If the device doesn't toggle the FID bit, invert stream->last_fid
* when the EOF bit is set to force synchronisation on the next packet.
*/
if (buf->state != UVC_BUF_STATE_ACTIVE) {
- if (fid == video->last_fid) {
+ if (fid == stream->last_fid) {
uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
"sync).\n");
- if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
+ if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
(data[1] & UVC_STREAM_EOF))
- video->last_fid ^= UVC_STREAM_FID;
+ stream->last_fid ^= UVC_STREAM_FID;
return -ENODATA;
}
@@ -422,7 +428,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* last payload can be lost anyway). We thus must check if the FID has
* been toggled.
*
- * video->last_fid is initialized to -1, so the first isochronous
+ * stream->last_fid is initialized to -1, so the first isochronous
* frame will never trigger an end of frame detection.
*
* Empty buffers (bytesused == 0) don't trigger end of frame detection
@@ -430,22 +436,22 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* avoids detecting end of frame conditions at FID toggling if the
* previous payload had the EOF bit set.
*/
- if (fid != video->last_fid && buf->buf.bytesused != 0) {
+ if (fid != stream->last_fid && buf->buf.bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
"toggled).\n");
buf->state = UVC_BUF_STATE_DONE;
return -EAGAIN;
}
- video->last_fid = fid;
+ stream->last_fid = fid;
return data[0];
}
-static void uvc_video_decode_data(struct uvc_video_device *video,
+static void uvc_video_decode_data(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len)
{
- struct uvc_video_queue *queue = &video->queue;
+ struct uvc_video_queue *queue = &stream->queue;
unsigned int maxlen, nbytes;
void *mem;
@@ -466,7 +472,7 @@ static void uvc_video_decode_data(struct uvc_video_device *video,
}
}
-static void uvc_video_decode_end(struct uvc_video_device *video,
+static void uvc_video_decode_end(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len)
{
/* Mark the buffer as done if the EOF marker is set. */
@@ -475,8 +481,8 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
if (data[0] == len)
uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
buf->state = UVC_BUF_STATE_DONE;
- if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
- video->last_fid ^= UVC_STREAM_FID;
+ if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
+ stream->last_fid ^= UVC_STREAM_FID;
}
}
@@ -491,26 +497,26 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
* uvc_video_encode_data is called for every URB and copies the data from the
* video buffer to the transfer buffer.
*/
-static int uvc_video_encode_header(struct uvc_video_device *video,
+static int uvc_video_encode_header(struct uvc_streaming *stream,
struct uvc_buffer *buf, __u8 *data, int len)
{
data[0] = 2; /* Header length */
data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
- | (video->last_fid & UVC_STREAM_FID);
+ | (stream->last_fid & UVC_STREAM_FID);
return 2;
}
-static int uvc_video_encode_data(struct uvc_video_device *video,
+static int uvc_video_encode_data(struct uvc_streaming *stream,
struct uvc_buffer *buf, __u8 *data, int len)
{
- struct uvc_video_queue *queue = &video->queue;
+ struct uvc_video_queue *queue = &stream->queue;
unsigned int nbytes;
void *mem;
/* Copy video data to the URB buffer. */
mem = queue->mem + buf->buf.m.offset + queue->buf_used;
nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
- nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size,
+ nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size,
nbytes);
memcpy(data, mem, nbytes);
@@ -526,8 +532,8 @@ static int uvc_video_encode_data(struct uvc_video_device *video,
/*
* Completion handler for video URBs.
*/
-static void uvc_video_decode_isoc(struct urb *urb,
- struct uvc_video_device *video, struct uvc_buffer *buf)
+static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
{
u8 *mem;
int ret, i;
@@ -542,31 +548,32 @@ static void uvc_video_decode_isoc(struct urb *urb,
/* Decode the payload header. */
mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
do {
- ret = uvc_video_decode_start(video, buf, mem,
+ ret = uvc_video_decode_start(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
if (ret == -EAGAIN)
- buf = uvc_queue_next_buffer(&video->queue, buf);
+ buf = uvc_queue_next_buffer(&stream->queue,
+ buf);
} while (ret == -EAGAIN);
if (ret < 0)
continue;
/* Decode the payload data. */
- uvc_video_decode_data(video, buf, mem + ret,
+ uvc_video_decode_data(stream, buf, mem + ret,
urb->iso_frame_desc[i].actual_length - ret);
/* Process the header again. */
- uvc_video_decode_end(video, buf, mem,
+ uvc_video_decode_end(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
if (buf->state == UVC_BUF_STATE_DONE ||
buf->state == UVC_BUF_STATE_ERROR)
- buf = uvc_queue_next_buffer(&video->queue, buf);
+ buf = uvc_queue_next_buffer(&stream->queue, buf);
}
}
-static void uvc_video_decode_bulk(struct urb *urb,
- struct uvc_video_device *video, struct uvc_buffer *buf)
+static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
{
u8 *mem;
int len, ret;
@@ -576,24 +583,25 @@ static void uvc_video_decode_bulk(struct urb *urb,
mem = urb->transfer_buffer;
len = urb->actual_length;
- video->bulk.payload_size += len;
+ stream->bulk.payload_size += len;
/* If the URB is the first of its payload, decode and save the
* header.
*/
- if (video->bulk.header_size == 0 && !video->bulk.skip_payload) {
+ if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
do {
- ret = uvc_video_decode_start(video, buf, mem, len);
+ ret = uvc_video_decode_start(stream, buf, mem, len);
if (ret == -EAGAIN)
- buf = uvc_queue_next_buffer(&video->queue, buf);
+ buf = uvc_queue_next_buffer(&stream->queue,
+ buf);
} while (ret == -EAGAIN);
/* If an error occured skip the rest of the payload. */
if (ret < 0 || buf == NULL) {
- video->bulk.skip_payload = 1;
+ stream->bulk.skip_payload = 1;
} else {
- memcpy(video->bulk.header, mem, ret);
- video->bulk.header_size = ret;
+ memcpy(stream->bulk.header, mem, ret);
+ stream->bulk.header_size = ret;
mem += ret;
len -= ret;
@@ -606,33 +614,34 @@ static void uvc_video_decode_bulk(struct urb *urb,
*/
/* Process video data. */
- if (!video->bulk.skip_payload && buf != NULL)
- uvc_video_decode_data(video, buf, mem, len);
+ if (!stream->bulk.skip_payload && buf != NULL)
+ uvc_video_decode_data(stream, buf, mem, len);
/* Detect the payload end by a URB smaller than the maximum size (or
* a payload size equal to the maximum) and process the header again.
*/
if (urb->actual_length < urb->transfer_buffer_length ||
- video->bulk.payload_size >= video->bulk.max_payload_size) {
- if (!video->bulk.skip_payload && buf != NULL) {
- uvc_video_decode_end(video, buf, video->bulk.header,
- video->bulk.payload_size);
+ stream->bulk.payload_size >= stream->bulk.max_payload_size) {
+ if (!stream->bulk.skip_payload && buf != NULL) {
+ uvc_video_decode_end(stream, buf, stream->bulk.header,
+ stream->bulk.payload_size);
if (buf->state == UVC_BUF_STATE_DONE ||
buf->state == UVC_BUF_STATE_ERROR)
- buf = uvc_queue_next_buffer(&video->queue, buf);
+ buf = uvc_queue_next_buffer(&stream->queue,
+ buf);
}
- video->bulk.header_size = 0;
- video->bulk.skip_payload = 0;
- video->bulk.payload_size = 0;
+ stream->bulk.header_size = 0;
+ stream->bulk.skip_payload = 0;
+ stream->bulk.payload_size = 0;
}
}
-static void uvc_video_encode_bulk(struct urb *urb,
- struct uvc_video_device *video, struct uvc_buffer *buf)
+static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
{
u8 *mem = urb->transfer_buffer;
- int len = video->urb_size, ret;
+ int len = stream->urb_size, ret;
if (buf == NULL) {
urb->transfer_buffer_length = 0;
@@ -640,40 +649,40 @@ static void uvc_video_encode_bulk(struct urb *urb,
}
/* If the URB is the first of its payload, add the header. */
- if (video->bulk.header_size == 0) {
- ret = uvc_video_encode_header(video, buf, mem, len);
- video->bulk.header_size = ret;
- video->bulk.payload_size += ret;
+ if (stream->bulk.header_size == 0) {
+ ret = uvc_video_encode_header(stream, buf, mem, len);
+ stream->bulk.header_size = ret;
+ stream->bulk.payload_size += ret;
mem += ret;
len -= ret;
}
/* Process video data. */
- ret = uvc_video_encode_data(video, buf, mem, len);
+ ret = uvc_video_encode_data(stream, buf, mem, len);
- video->bulk.payload_size += ret;
+ stream->bulk.payload_size += ret;
len -= ret;
- if (buf->buf.bytesused == video->queue.buf_used ||
- video->bulk.payload_size == video->bulk.max_payload_size) {
- if (buf->buf.bytesused == video->queue.buf_used) {
- video->queue.buf_used = 0;
+ if (buf->buf.bytesused == stream->queue.buf_used ||
+ stream->bulk.payload_size == stream->bulk.max_payload_size) {
+ if (buf->buf.bytesused == stream->queue.buf_used) {
+ stream->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE;
- uvc_queue_next_buffer(&video->queue, buf);
- video->last_fid ^= UVC_STREAM_FID;
+ uvc_queue_next_buffer(&stream->queue, buf);
+ stream->last_fid ^= UVC_STREAM_FID;
}
- video->bulk.header_size = 0;
- video->bulk.payload_size = 0;
+ stream->bulk.header_size = 0;
+ stream->bulk.payload_size = 0;
}
- urb->transfer_buffer_length = video->urb_size - len;
+ urb->transfer_buffer_length = stream->urb_size - len;
}
static void uvc_video_complete(struct urb *urb)
{
- struct uvc_video_device *video = urb->context;
- struct uvc_video_queue *queue = &video->queue;
+ struct uvc_streaming *stream = urb->context;
+ struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *buf = NULL;
unsigned long flags;
int ret;
@@ -687,7 +696,7 @@ static void uvc_video_complete(struct urb *urb)
"completion handler.\n", urb->status);
case -ENOENT: /* usb_kill_urb() called. */
- if (video->frozen)
+ if (stream->frozen)
return;
case -ECONNRESET: /* usb_unlink_urb() called. */
@@ -702,7 +711,7 @@ static void uvc_video_complete(struct urb *urb)
queue);
spin_unlock_irqrestore(&queue->irqlock, flags);
- video->decode(urb, video, buf);
+ stream->decode(urb, stream, buf);
if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
@@ -713,19 +722,19 @@ static void uvc_video_complete(struct urb *urb)
/*
* Free transfer buffers.
*/
-static void uvc_free_urb_buffers(struct uvc_video_device *video)
+static void uvc_free_urb_buffers(struct uvc_streaming *stream)
{
unsigned int i;
for (i = 0; i < UVC_URBS; ++i) {
- if (video->urb_buffer[i]) {
- usb_buffer_free(video->dev->udev, video->urb_size,
- video->urb_buffer[i], video->urb_dma[i]);
- video->urb_buffer[i] = NULL;
+ if (stream->urb_buffer[i]) {
+ usb_buffer_free(stream->dev->udev, stream->urb_size,
+ stream->urb_buffer[i], stream->urb_dma[i]);
+ stream->urb_buffer[i] = NULL;
}
}
- video->urb_size = 0;
+ stream->urb_size = 0;
}
/*
@@ -739,15 +748,15 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video)
*
* Return the number of allocated packets on success or 0 when out of memory.
*/
-static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
+static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
unsigned int size, unsigned int psize, gfp_t gfp_flags)
{
unsigned int npackets;
unsigned int i;
/* Buffers are already allocated, bail out. */
- if (video->urb_size)
- return video->urb_size / psize;
+ if (stream->urb_size)
+ return stream->urb_size / psize;
/* Compute the number of packets. Bulk endpoints might transfer UVC
* payloads accross multiple URBs.
@@ -759,17 +768,17 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
/* Retry allocations until one succeed. */
for (; npackets > 1; npackets /= 2) {
for (i = 0; i < UVC_URBS; ++i) {
- video->urb_buffer[i] = usb_buffer_alloc(
- video->dev->udev, psize * npackets,
- gfp_flags | __GFP_NOWARN, &video->urb_dma[i]);
- if (!video->urb_buffer[i]) {
- uvc_free_urb_buffers(video);
+ stream->urb_buffer[i] = usb_buffer_alloc(
+ stream->dev->udev, psize * npackets,
+ gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
+ if (!stream->urb_buffer[i]) {
+ uvc_free_urb_buffers(stream);
break;
}
}
if (i == UVC_URBS) {
- video->urb_size = psize * npackets;
+ stream->urb_size = psize * npackets;
return npackets;
}
}
@@ -780,29 +789,30 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
/*
* Uninitialize isochronous/bulk URBs and free transfer buffers.
*/
-static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers)
+static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
{
struct urb *urb;
unsigned int i;
for (i = 0; i < UVC_URBS; ++i) {
- if ((urb = video->urb[i]) == NULL)
+ urb = stream->urb[i];
+ if (urb == NULL)
continue;
usb_kill_urb(urb);
usb_free_urb(urb);
- video->urb[i] = NULL;
+ stream->urb[i] = NULL;
}
if (free_buffers)
- uvc_free_urb_buffers(video);
+ uvc_free_urb_buffers(stream);
}
/*
* Initialize isochronous URBs and allocate transfer buffers. The packet size
* is given by the endpoint.
*/
-static int uvc_init_video_isoc(struct uvc_video_device *video,
+static int uvc_init_video_isoc(struct uvc_streaming *stream,
struct usb_host_endpoint *ep, gfp_t gfp_flags)
{
struct urb *urb;
@@ -812,9 +822,9 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- size = video->streaming->ctrl.dwMaxVideoFrameSize;
+ size = stream->ctrl.dwMaxVideoFrameSize;
- npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+ npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
if (npackets == 0)
return -ENOMEM;
@@ -823,18 +833,18 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(npackets, gfp_flags);
if (urb == NULL) {
- uvc_uninit_video(video, 1);
+ uvc_uninit_video(stream, 1);
return -ENOMEM;
}
- urb->dev = video->dev->udev;
- urb->context = video;
- urb->pipe = usb_rcvisocpipe(video->dev->udev,
+ urb->dev = stream->dev->udev;
+ urb->context = stream;
+ urb->pipe = usb_rcvisocpipe(stream->dev->udev,
ep->desc.bEndpointAddress);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->interval = ep->desc.bInterval;
- urb->transfer_buffer = video->urb_buffer[i];
- urb->transfer_dma = video->urb_dma[i];
+ urb->transfer_buffer = stream->urb_buffer[i];
+ urb->transfer_dma = stream->urb_dma[i];
urb->complete = uvc_video_complete;
urb->number_of_packets = npackets;
urb->transfer_buffer_length = size;
@@ -844,7 +854,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
urb->iso_frame_desc[j].length = psize;
}
- video->urb[i] = urb;
+ stream->urb[i] = urb;
}
return 0;
@@ -854,7 +864,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
* Initialize bulk URBs and allocate transfer buffers. The packet size is
* given by the endpoint.
*/
-static int uvc_init_video_bulk(struct uvc_video_device *video,
+static int uvc_init_video_bulk(struct uvc_streaming *stream,
struct usb_host_endpoint *ep, gfp_t gfp_flags)
{
struct urb *urb;
@@ -863,39 +873,39 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
u32 size;
psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
- size = video->streaming->ctrl.dwMaxPayloadTransferSize;
- video->bulk.max_payload_size = size;
+ size = stream->ctrl.dwMaxPayloadTransferSize;
+ stream->bulk.max_payload_size = size;
- npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+ npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
if (npackets == 0)
return -ENOMEM;
size = npackets * psize;
if (usb_endpoint_dir_in(&ep->desc))
- pipe = usb_rcvbulkpipe(video->dev->udev,
+ pipe = usb_rcvbulkpipe(stream->dev->udev,
ep->desc.bEndpointAddress);
else
- pipe = usb_sndbulkpipe(video->dev->udev,
+ pipe = usb_sndbulkpipe(stream->dev->udev,
ep->desc.bEndpointAddress);
- if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
size = 0;
for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(0, gfp_flags);
if (urb == NULL) {
- uvc_uninit_video(video, 1);
+ uvc_uninit_video(stream, 1);
return -ENOMEM;
}
- usb_fill_bulk_urb(urb, video->dev->udev, pipe,
- video->urb_buffer[i], size, uvc_video_complete,
- video);
+ usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
+ stream->urb_buffer[i], size, uvc_video_complete,
+ stream);
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
- urb->transfer_dma = video->urb_dma[i];
+ urb->transfer_dma = stream->urb_dma[i];
- video->urb[i] = urb;
+ stream->urb[i] = urb;
}
return 0;
@@ -904,35 +914,35 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
/*
* Initialize isochronous/bulk URBs and allocate transfer buffers.
*/
-static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
+static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
{
- struct usb_interface *intf = video->streaming->intf;
+ struct usb_interface *intf = stream->intf;
struct usb_host_interface *alts;
struct usb_host_endpoint *ep = NULL;
- int intfnum = video->streaming->intfnum;
+ int intfnum = stream->intfnum;
unsigned int bandwidth, psize, i;
int ret;
- video->last_fid = -1;
- video->bulk.header_size = 0;
- video->bulk.skip_payload = 0;
- video->bulk.payload_size = 0;
+ stream->last_fid = -1;
+ stream->bulk.header_size = 0;
+ stream->bulk.skip_payload = 0;
+ stream->bulk.payload_size = 0;
if (intf->num_altsetting > 1) {
/* Isochronous endpoint, select the alternate setting. */
- bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize;
+ bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
if (bandwidth == 0) {
uvc_printk(KERN_WARNING, "device %s requested null "
"bandwidth, defaulting to lowest.\n",
- video->vdev->name);
+ stream->dev->name);
bandwidth = 1;
}
for (i = 0; i < intf->num_altsetting; ++i) {
alts = &intf->altsetting[i];
ep = uvc_find_endpoint(alts,
- video->streaming->header.bEndpointAddress);
+ stream->header.bEndpointAddress);
if (ep == NULL)
continue;
@@ -946,18 +956,19 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
if (i >= intf->num_altsetting)
return -EIO;
- if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0)
+ ret = usb_set_interface(stream->dev->udev, intfnum, i);
+ if (ret < 0)
return ret;
- ret = uvc_init_video_isoc(video, ep, gfp_flags);
+ ret = uvc_init_video_isoc(stream, ep, gfp_flags);
} else {
/* Bulk endpoint, proceed to URB initialization. */
ep = uvc_find_endpoint(&intf->altsetting[0],
- video->streaming->header.bEndpointAddress);
+ stream->header.bEndpointAddress);
if (ep == NULL)
return -EIO;
- ret = uvc_init_video_bulk(video, ep, gfp_flags);
+ ret = uvc_init_video_bulk(stream, ep, gfp_flags);
}
if (ret < 0)
@@ -965,10 +976,11 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
/* Submit the URBs. */
for (i = 0; i < UVC_URBS; ++i) {
- if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) {
+ ret = usb_submit_urb(stream->urb[i], gfp_flags);
+ if (ret < 0) {
uvc_printk(KERN_ERR, "Failed to submit URB %u "
"(%d).\n", i, ret);
- uvc_uninit_video(video, 1);
+ uvc_uninit_video(stream, 1);
return ret;
}
}
@@ -987,14 +999,14 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
* video buffers in any way. We mark the device as frozen to make sure the URB
* completion handler won't try to cancel the queue when we kill the URBs.
*/
-int uvc_video_suspend(struct uvc_video_device *video)
+int uvc_video_suspend(struct uvc_streaming *stream)
{
- if (!uvc_queue_streaming(&video->queue))
+ if (!uvc_queue_streaming(&stream->queue))
return 0;
- video->frozen = 1;
- uvc_uninit_video(video, 0);
- usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+ stream->frozen = 1;
+ uvc_uninit_video(stream, 0);
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
return 0;
}
@@ -1006,22 +1018,24 @@ int uvc_video_suspend(struct uvc_video_device *video)
* buffers, making sure userspace applications are notified of the problem
* instead of waiting forever.
*/
-int uvc_video_resume(struct uvc_video_device *video)
+int uvc_video_resume(struct uvc_streaming *stream)
{
int ret;
- video->frozen = 0;
+ stream->frozen = 0;
- if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) {
- uvc_queue_enable(&video->queue, 0);
+ ret = uvc_commit_video(stream, &stream->ctrl);
+ if (ret < 0) {
+ uvc_queue_enable(&stream->queue, 0);
return ret;
}
- if (!uvc_queue_streaming(&video->queue))
+ if (!uvc_queue_streaming(&stream->queue))
return 0;
- if ((ret = uvc_init_video(video, GFP_NOIO)) < 0)
- uvc_queue_enable(&video->queue, 0);
+ ret = uvc_init_video(stream, GFP_NOIO);
+ if (ret < 0)
+ uvc_queue_enable(&stream->queue, 0);
return ret;
}
@@ -1040,47 +1054,53 @@ int uvc_video_resume(struct uvc_video_device *video)
*
* This function is called before registering the device with V4L.
*/
-int uvc_video_init(struct uvc_video_device *video)
+int uvc_video_init(struct uvc_streaming *stream)
{
- struct uvc_streaming_control *probe = &video->streaming->ctrl;
+ struct uvc_streaming_control *probe = &stream->ctrl;
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
unsigned int i;
int ret;
- if (video->streaming->nformats == 0) {
+ if (stream->nformats == 0) {
uvc_printk(KERN_INFO, "No supported video formats found.\n");
return -EINVAL;
}
+ atomic_set(&stream->active, 0);
+
+ /* Initialize the video buffers queue. */
+ uvc_queue_init(&stream->queue, stream->type);
+
/* Alternate setting 0 should be the default, yet the XBox Live Vision
* Cam (and possibly other devices) crash or otherwise misbehave if
* they don't receive a SET_INTERFACE request before any other video
* control request.
*/
- usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
/* Set the streaming probe control with default streaming parameters
* retrieved from the device. Webcams that don't suport GET_DEF
* requests on the probe control will just keep their current streaming
* parameters.
*/
- if (uvc_get_video_ctrl(video, probe, 1, GET_DEF) == 0)
- uvc_set_video_ctrl(video, probe, 1);
+ if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
+ uvc_set_video_ctrl(stream, probe, 1);
/* Initialize the streaming parameters with the probe control current
* value. This makes sure SET_CUR requests on the streaming commit
* control will always use values retrieved from a successful GET_CUR
* request on the probe control, as required by the UVC specification.
*/
- if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
+ if (ret < 0)
return ret;
/* Check if the default format descriptor exists. Use the first
* available format otherwise.
*/
- for (i = video->streaming->nformats; i > 0; --i) {
- format = &video->streaming->format[i-1];
+ for (i = stream->nformats; i > 0; --i) {
+ format = &stream->format[i-1];
if (format->index == probe->bFormatIndex)
break;
}
@@ -1105,21 +1125,20 @@ int uvc_video_init(struct uvc_video_device *video)
probe->bFormatIndex = format->index;
probe->bFrameIndex = frame->bFrameIndex;
- video->streaming->cur_format = format;
- video->streaming->cur_frame = frame;
- atomic_set(&video->active, 0);
+ stream->cur_format = format;
+ stream->cur_frame = frame;
/* Select the video decoding function */
- if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
- video->decode = uvc_video_decode_isight;
- else if (video->streaming->intf->num_altsetting > 1)
- video->decode = uvc_video_decode_isoc;
+ if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+ stream->decode = uvc_video_decode_isight;
+ else if (stream->intf->num_altsetting > 1)
+ stream->decode = uvc_video_decode_isoc;
else
- video->decode = uvc_video_decode_bulk;
+ stream->decode = uvc_video_decode_bulk;
} else {
- if (video->streaming->intf->num_altsetting == 1)
- video->decode = uvc_video_encode_bulk;
+ if (stream->intf->num_altsetting == 1)
+ stream->decode = uvc_video_encode_bulk;
else {
uvc_printk(KERN_INFO, "Isochronous endpoints are not "
"supported for video output devices.\n");
@@ -1133,31 +1152,32 @@ int uvc_video_init(struct uvc_video_device *video)
/*
* Enable or disable the video stream.
*/
-int uvc_video_enable(struct uvc_video_device *video, int enable)
+int uvc_video_enable(struct uvc_streaming *stream, int enable)
{
int ret;
if (!enable) {
- uvc_uninit_video(video, 1);
- usb_set_interface(video->dev->udev,
- video->streaming->intfnum, 0);
- uvc_queue_enable(&video->queue, 0);
+ uvc_uninit_video(stream, 1);
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+ uvc_queue_enable(&stream->queue, 0);
return 0;
}
- if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+ if ((stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
uvc_no_drop_param)
- video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
+ stream->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
else
- video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+ stream->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
- if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
+ ret = uvc_queue_enable(&stream->queue, 1);
+ if (ret < 0)
return ret;
/* Commit the streaming parameters. */
- if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0)
+ ret = uvc_commit_video(stream, &stream->ctrl);
+ if (ret < 0)
return ret;
- return uvc_init_video(video, GFP_KERNEL);
+ return uvc_init_video(stream, GFP_KERNEL);
}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 3c78d3c1e4c0..e7958aa454ce 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -67,155 +67,12 @@ struct uvc_xu_control {
#ifdef __KERNEL__
#include <linux/poll.h>
+#include <linux/usb/video.h>
/* --------------------------------------------------------------------------
* UVC constants
*/
-#define SC_UNDEFINED 0x00
-#define SC_VIDEOCONTROL 0x01
-#define SC_VIDEOSTREAMING 0x02
-#define SC_VIDEO_INTERFACE_COLLECTION 0x03
-
-#define PC_PROTOCOL_UNDEFINED 0x00
-
-#define CS_UNDEFINED 0x20
-#define CS_DEVICE 0x21
-#define CS_CONFIGURATION 0x22
-#define CS_STRING 0x23
-#define CS_INTERFACE 0x24
-#define CS_ENDPOINT 0x25
-
-/* VideoControl class specific interface descriptor */
-#define VC_DESCRIPTOR_UNDEFINED 0x00
-#define VC_HEADER 0x01
-#define VC_INPUT_TERMINAL 0x02
-#define VC_OUTPUT_TERMINAL 0x03
-#define VC_SELECTOR_UNIT 0x04
-#define VC_PROCESSING_UNIT 0x05
-#define VC_EXTENSION_UNIT 0x06
-
-/* VideoStreaming class specific interface descriptor */
-#define VS_UNDEFINED 0x00
-#define VS_INPUT_HEADER 0x01
-#define VS_OUTPUT_HEADER 0x02
-#define VS_STILL_IMAGE_FRAME 0x03
-#define VS_FORMAT_UNCOMPRESSED 0x04
-#define VS_FRAME_UNCOMPRESSED 0x05
-#define VS_FORMAT_MJPEG 0x06
-#define VS_FRAME_MJPEG 0x07
-#define VS_FORMAT_MPEG2TS 0x0a
-#define VS_FORMAT_DV 0x0c
-#define VS_COLORFORMAT 0x0d
-#define VS_FORMAT_FRAME_BASED 0x10
-#define VS_FRAME_FRAME_BASED 0x11
-#define VS_FORMAT_STREAM_BASED 0x12
-
-/* Endpoint type */
-#define EP_UNDEFINED 0x00
-#define EP_GENERAL 0x01
-#define EP_ENDPOINT 0x02
-#define EP_INTERRUPT 0x03
-
-/* Request codes */
-#define RC_UNDEFINED 0x00
-#define SET_CUR 0x01
-#define GET_CUR 0x81
-#define GET_MIN 0x82
-#define GET_MAX 0x83
-#define GET_RES 0x84
-#define GET_LEN 0x85
-#define GET_INFO 0x86
-#define GET_DEF 0x87
-
-/* VideoControl interface controls */
-#define VC_CONTROL_UNDEFINED 0x00
-#define VC_VIDEO_POWER_MODE_CONTROL 0x01
-#define VC_REQUEST_ERROR_CODE_CONTROL 0x02
-
-/* Terminal controls */
-#define TE_CONTROL_UNDEFINED 0x00
-
-/* Selector Unit controls */
-#define SU_CONTROL_UNDEFINED 0x00
-#define SU_INPUT_SELECT_CONTROL 0x01
-
-/* Camera Terminal controls */
-#define CT_CONTROL_UNDEFINED 0x00
-#define CT_SCANNING_MODE_CONTROL 0x01
-#define CT_AE_MODE_CONTROL 0x02
-#define CT_AE_PRIORITY_CONTROL 0x03
-#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
-#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
-#define CT_FOCUS_ABSOLUTE_CONTROL 0x06
-#define CT_FOCUS_RELATIVE_CONTROL 0x07
-#define CT_FOCUS_AUTO_CONTROL 0x08
-#define CT_IRIS_ABSOLUTE_CONTROL 0x09
-#define CT_IRIS_RELATIVE_CONTROL 0x0a
-#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b
-#define CT_ZOOM_RELATIVE_CONTROL 0x0c
-#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d
-#define CT_PANTILT_RELATIVE_CONTROL 0x0e
-#define CT_ROLL_ABSOLUTE_CONTROL 0x0f
-#define CT_ROLL_RELATIVE_CONTROL 0x10
-#define CT_PRIVACY_CONTROL 0x11
-
-/* Processing Unit controls */
-#define PU_CONTROL_UNDEFINED 0x00
-#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
-#define PU_BRIGHTNESS_CONTROL 0x02
-#define PU_CONTRAST_CONTROL 0x03
-#define PU_GAIN_CONTROL 0x04
-#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05
-#define PU_HUE_CONTROL 0x06
-#define PU_SATURATION_CONTROL 0x07
-#define PU_SHARPNESS_CONTROL 0x08
-#define PU_GAMMA_CONTROL 0x09
-#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
-#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
-#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
-#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
-#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
-#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
-#define PU_HUE_AUTO_CONTROL 0x10
-#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
-#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12
-
-#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL 0x01
-#define LXU_MOTOR_PANTILT_RESET_CONTROL 0x02
-#define LXU_MOTOR_FOCUS_MOTOR_CONTROL 0x03
-
-/* VideoStreaming interface controls */
-#define VS_CONTROL_UNDEFINED 0x00
-#define VS_PROBE_CONTROL 0x01
-#define VS_COMMIT_CONTROL 0x02
-#define VS_STILL_PROBE_CONTROL 0x03
-#define VS_STILL_COMMIT_CONTROL 0x04
-#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
-#define VS_STREAM_ERROR_CODE_CONTROL 0x06
-#define VS_GENERATE_KEY_FRAME_CONTROL 0x07
-#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
-#define VS_SYNC_DELAY_CONTROL 0x09
-
-#define TT_VENDOR_SPECIFIC 0x0100
-#define TT_STREAMING 0x0101
-
-/* Input Terminal types */
-#define ITT_VENDOR_SPECIFIC 0x0200
-#define ITT_CAMERA 0x0201
-#define ITT_MEDIA_TRANSPORT_INPUT 0x0202
-
-/* Output Terminal types */
-#define OTT_VENDOR_SPECIFIC 0x0300
-#define OTT_DISPLAY 0x0301
-#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
-
-/* External Terminal types */
-#define EXTERNAL_VENDOR_SPECIFIC 0x0400
-#define COMPOSITE_CONNECTOR 0x0401
-#define SVIDEO_CONNECTOR 0x0402
-#define COMPONENT_CONNECTOR 0x0403
-
#define UVC_TERM_INPUT 0x0000
#define UVC_TERM_OUTPUT 0x8000
@@ -223,12 +80,12 @@ struct uvc_xu_control {
#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0)
#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0)
#define UVC_ENTITY_IS_ITERM(entity) \
- (((entity)->type & 0x8000) == UVC_TERM_INPUT)
+ (UVC_ENTITY_IS_TERM(entity) && \
+ ((entity)->type & 0x8000) == UVC_TERM_INPUT)
#define UVC_ENTITY_IS_OTERM(entity) \
- (((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
+ (UVC_ENTITY_IS_TERM(entity) && \
+ ((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
-#define UVC_STATUS_TYPE_CONTROL 1
-#define UVC_STATUS_TYPE_STREAMING 2
/* ------------------------------------------------------------------------
* GUIDs
@@ -249,19 +106,6 @@ struct uvc_xu_control {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
-#define UVC_GUID_LOGITECH_DEV_INFO \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}
-#define UVC_GUID_LOGITECH_USER_HW \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}
-#define UVC_GUID_LOGITECH_VIDEO \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x50}
-#define UVC_GUID_LOGITECH_MOTOR \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}
-
#define UVC_GUID_FORMAT_MJPEG \
{ 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -314,6 +158,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
+#define UVC_QUIRK_PROBE_DEF 0x00000100
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -518,26 +363,6 @@ struct uvc_streaming_header {
__u8 bTriggerUsage;
};
-struct uvc_streaming {
- struct list_head list;
-
- struct usb_interface *intf;
- int intfnum;
- __u16 maxpsize;
-
- struct uvc_streaming_header header;
- enum v4l2_buf_type type;
-
- unsigned int nformats;
- struct uvc_format *format;
-
- struct uvc_streaming_control ctrl;
- struct uvc_format *cur_format;
- struct uvc_frame *cur_frame;
-
- struct mutex mutex;
-};
-
enum uvc_buffer_state {
UVC_BUF_STATE_IDLE = 0,
UVC_BUF_STATE_QUEUED = 1,
@@ -579,26 +404,45 @@ struct uvc_video_queue {
struct list_head irqqueue;
};
-struct uvc_video_device {
+struct uvc_video_chain {
struct uvc_device *dev;
- struct video_device *vdev;
- atomic_t active;
- unsigned int frozen : 1;
+ struct list_head list;
struct list_head iterms; /* Input terminals */
- struct uvc_entity *oterm; /* Output terminal */
- struct uvc_entity *sterm; /* USB streaming terminal */
- struct uvc_entity *processing;
- struct uvc_entity *selector;
- struct list_head extensions;
+ struct list_head oterms; /* Output terminals */
+ struct uvc_entity *processing; /* Processing unit */
+ struct uvc_entity *selector; /* Selector unit */
+ struct list_head extensions; /* Extension units */
+
struct mutex ctrl_mutex;
+};
- struct uvc_video_queue queue;
+struct uvc_streaming {
+ struct list_head list;
+ struct uvc_device *dev;
+ struct video_device *vdev;
+ struct uvc_video_chain *chain;
+ atomic_t active;
- /* Video streaming object, must always be non-NULL. */
- struct uvc_streaming *streaming;
+ struct usb_interface *intf;
+ int intfnum;
+ __u16 maxpsize;
- void (*decode) (struct urb *urb, struct uvc_video_device *video,
+ struct uvc_streaming_header header;
+ enum v4l2_buf_type type;
+
+ unsigned int nformats;
+ struct uvc_format *format;
+
+ struct uvc_streaming_control ctrl;
+ struct uvc_format *cur_format;
+ struct uvc_frame *cur_frame;
+
+ struct mutex mutex;
+
+ unsigned int frozen : 1;
+ struct uvc_video_queue queue;
+ void (*decode) (struct urb *urb, struct uvc_streaming *video,
struct uvc_buffer *buf);
/* Context data used by the bulk completion handler. */
@@ -640,8 +484,10 @@ struct uvc_device {
__u32 clock_frequency;
struct list_head entities;
+ struct list_head chains;
- struct uvc_video_device video;
+ /* Video Streaming interfaces */
+ struct list_head streams;
/* Status Interrupt Endpoint */
struct usb_host_endpoint *int_ep;
@@ -649,9 +495,6 @@ struct uvc_device {
__u8 *status;
struct input_dev *input;
char input_phys[64];
-
- /* Video Streaming interfaces */
- struct list_head streaming;
};
enum uvc_handle_state {
@@ -660,7 +503,8 @@ enum uvc_handle_state {
};
struct uvc_fh {
- struct uvc_video_device *device;
+ struct uvc_video_chain *chain;
+ struct uvc_streaming *stream;
enum uvc_handle_state state;
};
@@ -757,13 +601,13 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
extern const struct v4l2_file_operations uvc_fops;
/* Video */
-extern int uvc_video_init(struct uvc_video_device *video);
-extern int uvc_video_suspend(struct uvc_video_device *video);
-extern int uvc_video_resume(struct uvc_video_device *video);
-extern int uvc_video_enable(struct uvc_video_device *video, int enable);
-extern int uvc_probe_video(struct uvc_video_device *video,
+extern int uvc_video_init(struct uvc_streaming *stream);
+extern int uvc_video_suspend(struct uvc_streaming *stream);
+extern int uvc_video_resume(struct uvc_streaming *stream);
+extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
+extern int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe);
-extern int uvc_commit_video(struct uvc_video_device *video,
+extern int uvc_commit_video(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl);
extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
__u8 intfnum, __u8 cs, void *data, __u16 size);
@@ -777,9 +621,9 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */
-extern struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping);
-extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl);
extern int uvc_ctrl_add_info(struct uvc_control_info *info);
@@ -789,23 +633,23 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
extern void uvc_ctrl_init(void);
-extern int uvc_ctrl_begin(struct uvc_video_device *video);
-extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback);
-static inline int uvc_ctrl_commit(struct uvc_video_device *video)
+extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
+extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
+static inline int uvc_ctrl_commit(struct uvc_video_chain *chain)
{
- return __uvc_ctrl_commit(video, 0);
+ return __uvc_ctrl_commit(chain, 0);
}
-static inline int uvc_ctrl_rollback(struct uvc_video_device *video)
+static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain)
{
- return __uvc_ctrl_commit(video, 1);
+ return __uvc_ctrl_commit(chain, 1);
}
-extern int uvc_ctrl_get(struct uvc_video_device *video,
+extern int uvc_ctrl_get(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl);
-extern int uvc_ctrl_set(struct uvc_video_device *video,
+extern int uvc_ctrl_set(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl);
-extern int uvc_xu_ctrl_query(struct uvc_video_device *video,
+extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control *ctrl, int set);
/* Utility functions */
@@ -817,7 +661,7 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
struct usb_host_interface *alts, __u8 epaddr);
/* Quirks support */
-void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
struct uvc_buffer *buf);
#endif /* __KERNEL__ */
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 02f2a6d18b45..761fbd64db58 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -76,9 +76,8 @@ get_v4l_control(struct file *file,
dprintk("VIDIOC_G_CTRL: %d\n", err);
return 0;
}
- return ((ctrl2.value - qctrl2.minimum) * 65535
- + (qctrl2.maximum - qctrl2.minimum) / 2)
- / (qctrl2.maximum - qctrl2.minimum);
+ return DIV_ROUND_CLOSEST((ctrl2.value-qctrl2.minimum) * 65535,
+ qctrl2.maximum - qctrl2.minimum);
}
return 0;
}
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index b91d66a767d7..3a0c64935b0e 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -156,6 +156,8 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
return -EINVAL;
if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_STRING)
+ return 0;
if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
@@ -340,6 +342,12 @@ const char **v4l2_ctrl_get_menu(u32 id)
"Sepia",
NULL
};
+ static const char *tune_preemphasis[] = {
+ "No preemphasis",
+ "50 useconds",
+ "75 useconds",
+ NULL,
+ };
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -378,6 +386,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
return camera_exposure_auto;
case V4L2_CID_COLORFX:
return colorfx;
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ return tune_preemphasis;
default:
return NULL;
}
@@ -476,6 +486,28 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
case V4L2_CID_PRIVACY: return "Privacy";
+ /* FM Radio Modulator control */
+ case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
+ case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
+ case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
+ case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
+ case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
+ case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
+ case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
+ case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
+ case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
+ case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
+ case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
+ case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
+
default:
return NULL;
}
@@ -508,6 +540,9 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
case V4L2_CID_FOCUS_AUTO:
case V4L2_CID_PRIVACY:
+ case V4L2_CID_AUDIO_LIMITER_ENABLED:
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+ case V4L2_CID_PILOT_TONE_ENABLED:
qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
min = 0;
max = step = 1;
@@ -536,12 +571,18 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_MPEG_STREAM_VBI_FMT:
case V4L2_CID_EXPOSURE_AUTO:
case V4L2_CID_COLORFX:
+ case V4L2_CID_TUNE_PREEMPHASIS:
qctrl->type = V4L2_CTRL_TYPE_MENU;
step = 1;
break;
+ case V4L2_CID_RDS_TX_PS_NAME:
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ qctrl->type = V4L2_CTRL_TYPE_STRING;
+ break;
case V4L2_CID_USER_CLASS:
case V4L2_CID_CAMERA_CLASS:
case V4L2_CID_MPEG_CLASS:
+ case V4L2_CID_FM_TX_CLASS:
qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
min = max = step = def = 0;
@@ -570,6 +611,17 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_BLUE_BALANCE:
case V4L2_CID_GAMMA:
case V4L2_CID_SHARPNESS:
+ case V4L2_CID_RDS_TX_DEVIATION:
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+ case V4L2_CID_PILOT_TONE_DEVIATION:
+ case V4L2_CID_PILOT_TONE_FREQUENCY:
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
break;
case V4L2_CID_PAN_RELATIVE:
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 0056b115b42e..997975d5e024 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -600,9 +600,37 @@ struct v4l2_ext_controls32 {
compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
};
+struct v4l2_ext_control32 {
+ __u32 id;
+ __u32 size;
+ __u32 reserved2[1];
+ union {
+ __s32 value;
+ __s64 value64;
+ compat_caddr_t string; /* actually char * */
+ };
+} __attribute__ ((packed));
+
+/* The following function really belong in v4l2-common, but that causes
+ a circular dependency between modules. We need to think about this, but
+ for now this will do. */
+
+/* Return non-zero if this control is a pointer type. Currently only
+ type STRING is a pointer type. */
+static inline int ctrl_is_pointer(u32 id)
+{
+ switch (id) {
+ case V4L2_CID_RDS_TX_PS_NAME:
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols;
int n;
compat_caddr_t p;
@@ -626,15 +654,17 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
kp->controls = kcontrols;
while (--n >= 0) {
- if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
- return -EFAULT;
- if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
- return -EFAULT;
- /* Note: if the void * part of the union ever becomes relevant
- then we need to know the type of the control in order to do
- the right thing here. Luckily, that is not yet an issue. */
- if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
return -EFAULT;
+ if (ctrl_is_pointer(kcontrols->id)) {
+ void __user *s;
+
+ if (get_user(p, &ucontrols->string))
+ return -EFAULT;
+ s = compat_ptr(p);
+ if (put_user(s, &kcontrols->string))
+ return -EFAULT;
+ }
ucontrols++;
kcontrols++;
}
@@ -643,7 +673,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols = kp->controls;
int n = kp->count;
compat_caddr_t p;
@@ -664,15 +694,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
return -EFAULT;
while (--n >= 0) {
- if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
- return -EFAULT;
- if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
- sizeof(ucontrols->reserved2)))
- return -EFAULT;
- /* Note: if the void * part of the union ever becomes relevant
- then we need to know the type of the control in order to do
- the right thing here. Luckily, that is not yet an issue. */
- if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
+ unsigned size = sizeof(*ucontrols);
+
+ /* Do not modify the pointer when copying a pointer control.
+ The contents of the pointer was changed, not the pointer
+ itself. */
+ if (ctrl_is_pointer(kcontrols->id))
+ size -= sizeof(ucontrols->value64);
+ if (copy_in_user(ucontrols, kcontrols, size))
return -EFAULT;
ucontrols++;
kcontrols++;
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index f2afc4e08379..30cc3347ae52 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -42,6 +42,12 @@
printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
} while (0)
+#define dbgarg3(fmt, arg...) \
+ do { \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\
+ } while (0)
+
/* Zero out the end of the struct pointed to by p. Everthing after, but
* not including, the specified field is cleared. */
#define CLEAR_AFTER_FIELD(p, field) \
@@ -507,11 +513,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd,
dbgarg(cmd, "");
printk(KERN_CONT "class=0x%x", c->ctrl_class);
for (i = 0; i < c->count; i++) {
- if (show_vals)
+ if (show_vals && !c->controls[i].size)
printk(KERN_CONT " id/val=0x%x/0x%x",
c->controls[i].id, c->controls[i].value);
else
- printk(KERN_CONT " id=0x%x", c->controls[i].id);
+ printk(KERN_CONT " id=0x%x,size=%u",
+ c->controls[i].id, c->controls[i].size);
}
printk(KERN_CONT "\n");
};
@@ -522,10 +529,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
/* zero the reserved fields */
c->reserved[0] = c->reserved[1] = 0;
- for (i = 0; i < c->count; i++) {
+ for (i = 0; i < c->count; i++)
c->controls[i].reserved2[0] = 0;
- c->controls[i].reserved2[1] = 0;
- }
+
/* V4L2_CID_PRIVATE_BASE cannot be used as control class
when using extended controls.
Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
@@ -1726,24 +1732,29 @@ static long __video_do_ioctl(struct file *file,
ret = ops->vidioc_enum_framesizes(file, fh, p);
dbgarg(cmd,
- "index=%d, pixelformat=%d, type=%d ",
- p->index, p->pixel_format, p->type);
+ "index=%d, pixelformat=%c%c%c%c, type=%d ",
+ p->index,
+ (p->pixel_format & 0xff),
+ (p->pixel_format >> 8) & 0xff,
+ (p->pixel_format >> 16) & 0xff,
+ (p->pixel_format >> 24) & 0xff,
+ p->type);
switch (p->type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
- dbgarg2("width = %d, height=%d\n",
+ dbgarg3("width = %d, height=%d\n",
p->discrete.width, p->discrete.height);
break;
case V4L2_FRMSIZE_TYPE_STEPWISE:
- dbgarg2("min %dx%d, max %dx%d, step %dx%d\n",
+ dbgarg3("min %dx%d, max %dx%d, step %dx%d\n",
p->stepwise.min_width, p->stepwise.min_height,
p->stepwise.step_width, p->stepwise.step_height,
p->stepwise.max_width, p->stepwise.max_height);
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
- dbgarg2("continuous\n");
+ dbgarg3("continuous\n");
break;
default:
- dbgarg2("- Unknown type!\n");
+ dbgarg3("- Unknown type!\n");
}
break;
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 97b082fe4473..f3b6e15d91f2 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -1776,7 +1776,6 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
static struct i2c_adapter vino_i2c_adapter = {
.name = "VINO I2C bus",
- .id = I2C_HW_SGI_VINO,
.algo = &sgi_algo,
.algo_data = &i2c_sgi_vino_data,
.owner = THIS_MODULE,
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 6c3f23e31b5c..602484dd3da9 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -1497,7 +1497,6 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
};
static struct i2c_adapter adap = {
- .id = I2C_HW_SMBUS_W9968CF,
.owner = THIS_MODULE,
.algo = &algo,
};
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 03dc2f3cf84a..0c4d9b1f8e6f 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -732,7 +732,6 @@ zoran_register_i2c (struct zoran *zr)
memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
sizeof(struct i2c_algo_bit_data));
zr->i2c_algo.data = zr;
- zr->i2c_adapter.id = I2C_HW_B_ZR36067;
strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
sizeof(zr->i2c_adapter.name));
i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev);
@@ -1169,7 +1168,7 @@ zoran_setup_videocodec (struct zoran *zr,
m->type = 0;
m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
- strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
+ strlcpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
m->data = zr;
switch (type)
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 2622a6e63da1..9aae011d92ab 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -1,5 +1,5 @@
/*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
*
* Allows you to use your USB webcam with V4L2 applications
* This is still in heavy developpement !
@@ -10,6 +10,8 @@
* Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
* V4L2 version inspired by meye.c driver
*
+ * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
+ *
* 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
@@ -27,6 +29,7 @@
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
@@ -35,24 +38,40 @@
#include <linux/highmem.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
/* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define DRIVER_VERSION "v0.73"
+#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3)
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
-#define FRAMES 2
-#define MAX_FRAME_SIZE 100000
+#define FRAMES 1
+#define MAX_FRAME_SIZE 200000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
+#define ZR364XX_DEF_BUFS 4
+#define ZR364XX_READ_IDLE 0
+#define ZR364XX_READ_FRAME 1
/* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
-
+#define DBG(fmt, args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+ } \
+ } while (0)
+
+/*#define FULL_DEBUG 1*/
+#ifdef FULL_DEBUG
+#define _DBG DBG
+#else
+#define _DBG(fmt, args...)
+#endif
/* Init methods, need to find nicer names for these
* the exact names of the chipsets would be the best if someone finds it */
@@ -101,24 +120,93 @@ static struct usb_device_id device_table[] = {
MODULE_DEVICE_TABLE(usb, device_table);
+struct zr364xx_mode {
+ u32 color; /* output video color format */
+ u32 brightness; /* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+ unsigned long ulState; /* ulState:ZR364XX_READ_IDLE,
+ ZR364XX_READ_FRAME */
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+ struct list_head active;
+ struct zr364xx_camera *cam;
+};
+
+struct zr364xx_pipeinfo {
+ u32 transfer_size;
+ u8 *transfer_buffer;
+ u32 state;
+ void *stream_urb;
+ void *cam; /* back pointer to zr364xx_camera struct */
+ u32 err_count;
+ u32 idx;
+};
+
+struct zr364xx_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* image formats. */
+static const struct zr364xx_fmt formats[] = {
+ {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }
+};
/* Camera stuff */
struct zr364xx_camera {
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface;/* the interface for this device */
struct video_device *vdev; /* v4l video device */
- u8 *framebuf;
int nb;
- unsigned char *buffer;
+ struct zr364xx_bufferi buffer;
int skip;
- int brightness;
int width;
int height;
int method;
struct mutex lock;
+ struct mutex open_lock;
int users;
+
+ spinlock_t slock;
+ struct zr364xx_dmaqueue vidq;
+ int resources;
+ int last_frame;
+ int cur_frame;
+ unsigned long frame_count;
+ int b_acquire;
+ struct zr364xx_pipeinfo pipe[1];
+
+ u8 read_endpoint;
+
+ const struct zr364xx_fmt *fmt;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ struct zr364xx_mode mode;
};
+/* buffer for one video frame */
+struct zr364xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct zr364xx_fmt *fmt;
+};
/* function used to send initialisation commands to the camera */
static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -272,139 +360,116 @@ static unsigned char header2[] = {
};
static unsigned char header3;
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
-/********************/
-/* V4L2 integration */
-/********************/
+ *size = cam->width * cam->height * (cam->fmt->depth >> 3);
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
- int i, n, temp, head, size, actual_length;
- unsigned char *ptr = NULL, *jpeg;
-
- redo:
- /* hardware brightness */
- n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
- temp = (0x60 << 8) + 127 - cam->brightness;
- n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
- /* during the first loop we are going to insert JPEG header */
- head = 0;
- /* this is the place in memory where we are going to build
- * the JPEG image */
- jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
- /* read data... */
- do {
- n = usb_bulk_msg(cam->udev,
- usb_rcvbulkpipe(cam->udev, 0x81),
- cam->buffer, BUFFER_SIZE, &actual_length,
- CTRL_TIMEOUT);
- DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
- DBG("bulk : n=%d size=%d", n, actual_length);
- if (n < 0) {
- dev_err(&cam->udev->dev, "error reading bulk msg\n");
- return 0;
- }
- if (actual_length < 0 || actual_length > BUFFER_SIZE) {
- dev_err(&cam->udev->dev, "wrong number of bytes\n");
- return 0;
- }
+ if (*count == 0)
+ *count = ZR364XX_DEF_BUFS;
- /* swap bytes if camera needs it */
- if (cam->method == METHOD0) {
- u16 *buf = (u16*)cam->buffer;
- for (i = 0; i < BUFFER_SIZE/2; i++)
- swab16s(buf + i);
- }
+ while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+ (*count)--;
- /* write the JPEG header */
- if (!head) {
- DBG("jpeg header");
- ptr = jpeg;
- memcpy(ptr, header1, sizeof(header1));
- ptr += sizeof(header1);
- header3 = 0;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer, 64);
- ptr += 64;
- header3 = 1;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer + 64, 64);
- ptr += 64;
- memcpy(ptr, header2, sizeof(header2));
- ptr += sizeof(header2);
- memcpy(ptr, cam->buffer + 128,
- actual_length - 128);
- ptr += actual_length - 128;
- head = 1;
- DBG("header : %d %d %d %d %d %d %d %d %d",
- cam->buffer[0], cam->buffer[1], cam->buffer[2],
- cam->buffer[3], cam->buffer[4], cam->buffer[5],
- cam->buffer[6], cam->buffer[7], cam->buffer[8]);
- } else {
- memcpy(ptr, cam->buffer, actual_length);
- ptr += actual_length;
- }
- }
- /* ... until there is no more */
- while (actual_length == BUFFER_SIZE);
+ return 0;
+}
- /* we skip the 2 first frames which are usually buggy */
- if (cam->skip) {
- cam->skip--;
- goto redo;
- }
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf)
+{
+ _DBG("%s\n", __func__);
- /* go back to find the JPEG EOI marker */
- size = ptr - jpeg;
- ptr -= 2;
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xD9
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr == jpeg)
- DBG("No EOI marker");
+ if (in_interrupt())
+ BUG();
- /* Sometimes there is junk data in the middle of the picture,
- * we want to skip this bogus frames */
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xFF
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ int rc;
+
+ DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
+ cam->fmt->name : "");
+ if (cam->fmt == NULL)
+ return -EINVAL;
+
+ buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+ DBG("invalid buffer prepare\n");
+ return -EINVAL;
}
- if (ptr != jpeg) {
- DBG("Bogus frame ? %d", cam->nb);
- goto redo;
+
+ buf->fmt = cam->fmt;
+ buf->vb.width = cam->width;
+ buf->vb.height = cam->height;
+ buf->vb.field = field;
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
}
- DBG("jpeg : %d %d %d %d %d %d %d %d",
- jpeg[0], jpeg[1], jpeg[2], jpeg[3],
- jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ struct zr364xx_camera *cam = vq->priv_data;
+
+ _DBG("%s\n", __func__);
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &cam->vidq.active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
- return size;
+ _DBG("%s\n", __func__);
+ free_buffer(vq, buf);
}
+static struct videobuf_queue_ops zr364xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************/
+/* V4L2 integration */
+/********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type);
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
loff_t * ppos)
{
- unsigned long count = cnt;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
- DBG("zr364xx_read: read %d bytes.", (int) count);
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ _DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -412,21 +477,276 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
if (!count)
return -EINVAL;
- /* NoMan Sux ! */
- count = read_frame(cam, 0);
+ if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
+ DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
+ (int) *ppos);
+
+ /* NoMan Sux ! */
+ return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ }
+
+ return 0;
+}
+
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void zr364xx_fillbuff(struct zr364xx_camera *cam,
+ struct zr364xx_buffer *buf,
+ int jpgsize)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+ struct zr364xx_framei *frm;
+
+ if (!vbuf)
+ return;
+
+ last_frame = cam->last_frame;
+ if (last_frame != -1) {
+ frm = &cam->buffer.frame[last_frame];
+ tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
+ switch (buf->fmt->fourcc) {
+ case V4L2_PIX_FMT_JPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
+ default:
+ printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
+ }
+ cam->last_frame = -1;
+ } else {
+ printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
+ return;
+ }
+ DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count = cam->frame_count * 2;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
+{
+ struct zr364xx_dmaqueue *dma_q = &cam->vidq;
+ struct zr364xx_buffer *buf;
+ unsigned long flags = 0;
+ int rc = 0;
+
+ DBG("wakeup: %p\n", &dma_q);
+ spin_lock_irqsave(&cam->slock, flags);
+
+ if (list_empty(&dma_q->active)) {
+ DBG("No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct zr364xx_buffer, vb.queue);
+
+ if (!waitqueue_active(&buf->vb.done)) {
+ /* no one active */
+ rc = -1;
+ goto unlock;
+ }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
+ zr364xx_fillbuff(cam, buf, jpgsize);
+ wake_up(&buf->vb.done);
+ DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&cam->slock, flags);
+ return 0;
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process (call this
+ * function again).
+ */
+static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
+ struct zr364xx_pipeinfo *pipe_info,
+ struct urb *purb)
+{
+ unsigned char *pdest;
+ unsigned char *psrc;
+ s32 idx = -1;
+ struct zr364xx_framei *frm;
+ int i = 0;
+ unsigned char *ptr = NULL;
+
+ _DBG("buffer to user\n");
+ idx = cam->cur_frame;
+ frm = &cam->buffer.frame[idx];
+
+ /* swap bytes if camera needs it */
+ if (cam->method == METHOD0) {
+ u16 *buf = (u16 *)pipe_info->transfer_buffer;
+ for (i = 0; i < purb->actual_length/2; i++)
+ swab16s(buf + i);
+ }
+
+ /* search done. now find out if should be acquiring */
+ if (!cam->b_acquire) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = ZR364XX_READ_IDLE;
+ return -EINVAL;
+ }
+
+ psrc = (u8 *)pipe_info->transfer_buffer;
+ ptr = pdest = frm->lpvbits;
+
+ if (frm->ulState == ZR364XX_READ_IDLE) {
+ frm->ulState = ZR364XX_READ_FRAME;
+ frm->cur_size = 0;
+
+ _DBG("jpeg header, ");
+ memcpy(ptr, header1, sizeof(header1));
+ ptr += sizeof(header1);
+ header3 = 0;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc, 64);
+ ptr += 64;
+ header3 = 1;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc + 64, 64);
+ ptr += 64;
+ memcpy(ptr, header2, sizeof(header2));
+ ptr += sizeof(header2);
+ memcpy(ptr, psrc + 128,
+ purb->actual_length - 128);
+ ptr += purb->actual_length - 128;
+ _DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ psrc[0], psrc[1], psrc[2],
+ psrc[3], psrc[4], psrc[5],
+ psrc[6], psrc[7], psrc[8]);
+ frm->cur_size = ptr - pdest;
+ } else {
+ if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) {
+ dev_info(&cam->udev->dev,
+ "%s: buffer (%d bytes) too small to hold "
+ "frame data. Discarding frame data.\n",
+ __func__, MAX_FRAME_SIZE);
+ } else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
+ }
+ /*_DBG("cur_size %lu urb size %d\n", frm->cur_size,
+ purb->actual_length);*/
+
+ if (purb->actual_length < pipe_info->transfer_size) {
+ _DBG("****************Buffer[%d]full*************\n", idx);
+ cam->last_frame = cam->cur_frame;
+ cam->cur_frame++;
+ /* end of system frame ring buffer, start at zero */
+ if (cam->cur_frame == cam->buffer.dwFrames)
+ cam->cur_frame = 0;
+
+ /* frame ready */
+ /* go back to find the JPEG EOI marker */
+ ptr = pdest = frm->lpvbits;
+ ptr += frm->cur_size - 2;
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr == pdest)
+ DBG("No EOI marker\n");
+
+ /* Sometimes there is junk data in the middle of the picture,
+ * we want to skip this bogus frames */
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr != pdest) {
+ DBG("Bogus frame ? %d\n", ++(cam->nb));
+ } else if (cam->b_acquire) {
+ /* we skip the 2 first frames which are usually buggy */
+ if (cam->skip)
+ cam->skip--;
+ else {
+ _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+ frm->cur_size,
+ pdest[0], pdest[1], pdest[2], pdest[3],
+ pdest[4], pdest[5], pdest[6], pdest[7]);
+
+ zr364xx_got_frame(cam, frm->cur_size);
+ }
+ }
+ cam->frame_count++;
+ frm->ulState = ZR364XX_READ_IDLE;
+ frm->cur_size = 0;
+ }
+ /* done successfully */
+ return 0;
+}
- if (copy_to_user(buf, cam->framebuf, count))
- return -EFAULT;
+static int res_get(struct zr364xx_camera *cam)
+{
+ /* is it free? */
+ mutex_lock(&cam->lock);
+ if (cam->resources) {
+ /* no, someone else uses it */
+ mutex_unlock(&cam->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ cam->resources = 1;
+ _DBG("res: get\n");
+ mutex_unlock(&cam->lock);
+ return 1;
+}
- return count;
+static inline int res_check(struct zr364xx_camera *cam)
+{
+ return cam->resources;
}
+static void res_free(struct zr364xx_camera *cam)
+{
+ mutex_lock(&cam->lock);
+ cam->resources = 0;
+ mutex_unlock(&cam->lock);
+ _DBG("res: put\n");
+}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strcpy(cap->driver, DRIVER_DESC);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+ strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
+ sizeof(cap->bus_info));
+ cap->version = ZR364XX_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
return 0;
}
@@ -458,12 +778,11 @@ static int zr364xx_vidioc_s_input(struct file *file, void *priv,
static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
@@ -472,7 +791,7 @@ static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
c->minimum = 0;
c->maximum = 127;
c->step = 1;
- c->default_value = cam->brightness;
+ c->default_value = cam->mode.brightness;
c->flags = 0;
break;
default:
@@ -484,36 +803,42 @@ static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
+ int temp;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- cam->brightness = c->value;
+ cam->mode.brightness = c->value;
+ /* hardware brightness */
+ mutex_lock(&cam->lock);
+ send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+ temp = (0x60 << 8) + 127 - cam->mode.brightness;
+ send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+ mutex_unlock(&cam->lock);
break;
default:
return -EINVAL;
}
+
return 0;
}
static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- c->value = cam->brightness;
+ c->value = cam->mode.brightness;
break;
default:
return -EINVAL;
@@ -527,47 +852,63 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
if (f->index > 0)
return -EINVAL;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "JPEG");
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ strcpy(f->description, formats[0].name);
+ f->pixelformat = formats[0].fourcc;
return 0;
}
+static char *decode_fourcc(__u32 pixelformat, char *buf)
+{
+ buf[0] = pixelformat & 0xff;
+ buf[1] = (pixelformat >> 8) & 0xff;
+ buf[2] = (pixelformat >> 16) & 0xff;
+ buf[3] = (pixelformat >> 24) & 0xff;
+ buf[4] = '\0';
+ return buf;
+}
+
static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ char pixelformat_name[5];
- if (vdev == NULL)
+ if (cam == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
+ DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
return -EINVAL;
+ }
+
+ if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) &&
+ !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ }
+
f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
return 0;
}
static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+ f->fmt.pix.pixelformat = formats[0].fourcc;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -581,38 +922,327 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ char pixelformat_name[5];
+ int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+ int i;
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ if (ret < 0)
+ return ret;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&cam->vb_vidq)) {
+ DBG("%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (res_check(cam)) {
+ DBG("%s can't change format after started\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ cam->width = f->fmt.pix.width;
+ cam->height = f->fmt.pix.height;
+ dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+ cam->width, cam->height);
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
- DBG("ok!");
+ cam->vb_vidq.field = f->fmt.pix.field;
+ cam->mode.color = V4L2_PIX_FMT_JPEG;
+
+ if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
+ mode = 1;
+ else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480)
+ mode = 2;
+ else
+ mode = 0;
+
+ m0d1[0] = mode;
+ m1[2].value = 0xf000 + mode;
+ m2[1].value = 0xf000 + mode;
+ header2[437] = cam->height / 256;
+ header2[438] = cam->height % 256;
+ header2[439] = cam->width / 256;
+ header2[440] = cam->width % 256;
+
+ for (i = 0; init[cam->method][i].size != -1; i++) {
+ ret =
+ send_control_msg(cam->udev, 1, init[cam->method][i].value,
+ 0, init[cam->method][i].bytes,
+ init[cam->method][i].size);
+ if (ret < 0) {
+ dev_err(&cam->udev->dev,
+ "error during resolution change sequence: %d\n", i);
+ goto out;
+ }
+ }
+
+ /* Added some delay here, since opening/closing the camera quickly,
+ * like Ekiga does during its startup, can crash the webcam
+ */
+ mdelay(100);
+ cam->skip = 2;
+ ret = 0;
+
+out:
+ mutex_unlock(&q->vb_lock);
+
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
+ return ret;
+}
+
+static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_reqbufs(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_querybuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_querybuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_qbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ _DBG("%s\n", __func__);
+ rc = videobuf_qbuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_dqbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ _DBG("%s\n", __func__);
+ rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return rc;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+ struct zr364xx_camera *cam;
+ int pipe;
+
+ pipe_info = purb->context;
+ _DBG("%s %p, status %d\n", __func__, purb, purb->status);
+ if (pipe_info == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ cam = pipe_info->cam;
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ /* if shutting down, do not resubmit, exit immediately */
+ if (purb->status == -ESHUTDOWN) {
+ DBG("%s, err shutdown\n", __func__);
+ pipe_info->err_count++;
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ DBG("exiting USB pipe\n");
+ return;
+ }
+
+ if (purb->actual_length < 0 ||
+ purb->actual_length > pipe_info->transfer_size) {
+ dev_err(&cam->udev->dev, "wrong number of bytes\n");
+ return;
+ }
+
+ if (purb->status == 0)
+ zr364xx_read_video_callback(cam, pipe_info, purb);
+ else {
+ pipe_info->err_count++;
+ DBG("%s: failed URB %d\n", __func__, purb->status);
+ }
+
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ purb->status = usb_submit_urb(pipe_info->stream_urb,
+ GFP_ATOMIC);
+
+ if (purb->status)
+ dev_err(&cam->udev->dev,
+ "error submitting urb (error=%i)\n",
+ purb->status);
+ } else
+ DBG("read pipe complete state 0\n");
+}
+
+static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
+{
+ int pipe;
+ int retval;
+ struct zr364xx_pipeinfo *pipe_info = cam->pipe;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+ DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
+
+ pipe_info->state = 1;
+ pipe_info->err_count = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ DBG("submitting URB %p\n", pipe_info->stream_urb);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
+ return;
+ }
+ DBG("stop read pipe\n");
+ pipe_info = cam->pipe;
+ if (pipe_info) {
+ if (pipe_info->state != 0)
+ pipe_info->state = 0;
+
+ if (pipe_info->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe_info->stream_urb);
+ usb_free_urb(pipe_info->stream_urb);
+ pipe_info->stream_urb = NULL;
+ }
+ }
+ return;
+}
+
+/* starts acquisition process */
+static int zr364xx_start_acquire(struct zr364xx_camera *cam)
+{
+ int j;
+
+ DBG("start acquire\n");
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ cam->b_acquire = 1;
+ return 0;
+}
+
+static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
+{
+ cam->b_acquire = 0;
return 0;
}
static int zr364xx_vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- return 0;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int j;
+ int res;
+
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+
+ if (!res_get(cam)) {
+ dev_err(&cam->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ cam->frame_count = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&cam->vb_vidq);
+ if (res == 0) {
+ zr364xx_start_acquire(cam);
+ } else {
+ res_free(cam);
+ }
+ return res;
}
static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
+ int res;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ DBG("%s\n", __func__);
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+ zr364xx_stop_acquire(cam);
+ res = videobuf_streamoff(&cam->vb_vidq);
+ if (res < 0)
+ return res;
+ res_free(cam);
return 0;
}
@@ -621,28 +1251,19 @@ static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
static int zr364xx_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
struct usb_device *udev = cam->udev;
int i, err;
- DBG("zr364xx_open");
+ DBG("%s\n", __func__);
- mutex_lock(&cam->lock);
+ mutex_lock(&cam->open_lock);
if (cam->users) {
err = -EBUSY;
goto out;
}
- if (!cam->framebuf) {
- cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
- if (!cam->framebuf) {
- dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
- err = -ENOMEM;
- goto out;
- }
- }
-
for (i = 0; init[cam->method][i].size != -1; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -658,6 +1279,14 @@ static int zr364xx_open(struct file *file)
cam->skip = 2;
cam->users++;
file->private_data = vdev;
+ cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->fmt = formats;
+
+ videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+ NULL, &cam->slock,
+ cam->type,
+ V4L2_FIELD_NONE,
+ sizeof(struct zr364xx_buffer), cam);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
@@ -666,28 +1295,70 @@ static int zr364xx_open(struct file *file)
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+ DBG("%s: %d\n", __func__, err);
return err;
}
+static void zr364xx_destroy(struct zr364xx_camera *cam)
+{
+ unsigned long i;
+
+ if (!cam) {
+ printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
+ return;
+ }
+ mutex_lock(&cam->open_lock);
+ if (cam->vdev)
+ video_unregister_device(cam->vdev);
+ cam->vdev = NULL;
+
+ /* stops the read pipe if it is running */
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+
+ zr364xx_stop_readpipe(cam);
+
+ /* release sys buffers */
+ for (i = 0; i < FRAMES; i++) {
+ if (cam->buffer.frame[i].lpvbits) {
+ DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
+ vfree(cam->buffer.frame[i].lpvbits);
+ }
+ cam->buffer.frame[i].lpvbits = NULL;
+ }
+
+ /* release transfer buffer */
+ kfree(cam->pipe->transfer_buffer);
+ cam->pipe->transfer_buffer = NULL;
+ mutex_unlock(&cam->open_lock);
+ kfree(cam);
+ cam = NULL;
+}
/* release the camera */
static int zr364xx_release(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
struct usb_device *udev;
int i, err;
- DBG("zr364xx_release");
+ DBG("%s\n", __func__);
+ cam = video_drvdata(file);
- if (vdev == NULL)
+ if (!cam)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ mutex_lock(&cam->open_lock);
udev = cam->udev;
- mutex_lock(&cam->lock);
+ /* turn off stream */
+ if (res_check(cam)) {
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+ videobuf_streamoff(&cam->vb_vidq);
+ res_free(cam);
+ }
cam->users--;
file->private_data = NULL;
@@ -710,40 +1381,43 @@ static int zr364xx_release(struct file *file)
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+
return err;
}
static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
{
- void *pos;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- DBG("zr364xx_mmap: %ld\n", size);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int ret;
- if (vdev == NULL)
+ if (cam == NULL) {
+ DBG("%s: cam == NULL\n", __func__);
return -ENODEV;
- cam = video_get_drvdata(vdev);
-
- pos = cam->framebuf;
- while (size > 0) {
- if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
}
+ DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
- return 0;
+ ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
+
+ DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+ return ret;
}
+static unsigned int zr364xx_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ _DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
@@ -752,6 +1426,7 @@ static const struct v4l2_file_operations zr364xx_fops = {
.read = zr364xx_read,
.mmap = zr364xx_mmap,
.ioctl = video_ioctl2,
+ .poll = zr364xx_poll,
};
static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
@@ -768,6 +1443,10 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
.vidioc_queryctrl = zr364xx_vidioc_queryctrl,
.vidioc_g_ctrl = zr364xx_vidioc_g_ctrl,
.vidioc_s_ctrl = zr364xx_vidioc_s_ctrl,
+ .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
+ .vidioc_querybuf = zr364xx_vidioc_querybuf,
+ .vidioc_qbuf = zr364xx_vidioc_qbuf,
+ .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
};
static struct video_device zr364xx_template = {
@@ -783,15 +1462,76 @@ static struct video_device zr364xx_template = {
/*******************/
/* USB integration */
/*******************/
+static int zr364xx_board_init(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe = cam->pipe;
+ unsigned long i;
+
+ DBG("board init: %p\n", cam);
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->cam = cam;
+ pipe->transfer_size = BUFFER_SIZE;
+
+ pipe->transfer_buffer = kzalloc(pipe->transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ DBG("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ cam->b_acquire = 0;
+ cam->frame_count = 0;
+
+ /*** start create system buffers ***/
+ for (i = 0; i < FRAMES; i++) {
+ /* always allocate maximum size for system buffers */
+ cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
+
+ DBG("valloc %p, idx %lu, pdata %p\n",
+ &cam->buffer.frame[i], i,
+ cam->buffer.frame[i].lpvbits);
+ if (cam->buffer.frame[i].lpvbits == NULL) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. "
+ "Using less frames\n");
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
+ kfree(cam->pipe->transfer_buffer);
+ cam->pipe->transfer_buffer = NULL;
+ return -ENOMEM;
+ } else
+ cam->buffer.dwFrames = i;
+
+ /* make sure internal states are set */
+ for (i = 0; i < FRAMES; i++) {
+ cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[i].cur_size = 0;
+ }
+
+ cam->cur_frame = 0;
+ cam->last_frame = -1;
+ /*** end create system buffers ***/
+
+ /* start read pipe */
+ zr364xx_start_readpipe(cam);
+ DBG(": board initialized\n");
+ return 0;
+}
static int zr364xx_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
int err;
+ int i;
- DBG("probing...");
+ DBG("probing...\n");
dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
dev_info(&intf->dev, "model %04x:%04x detected\n",
@@ -810,22 +1550,17 @@ static int zr364xx_probe(struct usb_interface *intf,
if (cam->vdev == NULL) {
dev_err(&udev->dev, "cam->vdev: out of memory !\n");
kfree(cam);
+ cam = NULL;
return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+ cam->vdev->parent = &intf->dev;
video_set_drvdata(cam->vdev, cam);
if (debug)
cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->udev = udev;
- if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
- dev_info(&udev->dev, "cam->buffer: out of memory !\n");
- video_device_release(cam->vdev);
- kfree(cam);
- return -ENODEV;
- }
-
switch (mode) {
case 1:
dev_info(&udev->dev, "160x120 mode selected\n");
@@ -852,21 +1587,53 @@ static int zr364xx_probe(struct usb_interface *intf,
header2[439] = cam->width / 256;
header2[440] = cam->width % 256;
+ cam->users = 0;
cam->nb = 0;
- cam->brightness = 64;
+ cam->mode.brightness = 64;
mutex_init(&cam->lock);
+ mutex_init(&cam->open_lock);
+
+ DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
+
+ /* set up the endpoint information */
+ iface_desc = intf->cur_altsetting;
+ DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found the bulk in endpoint */
+ cam->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!cam->read_endpoint) {
+ dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+ return -ENOMEM;
+ }
+ /* v4l */
+ INIT_LIST_HEAD(&cam->vidq.active);
+ cam->vidq.cam = cam;
err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
if (err) {
dev_err(&udev->dev, "video_register_device failed\n");
video_device_release(cam->vdev);
- kfree(cam->buffer);
kfree(cam);
+ cam = NULL;
return err;
}
usb_set_intfdata(intf, cam);
+ /* load zr364xx board specific */
+ err = zr364xx_board_init(cam);
+ if (err) {
+ spin_lock_init(&cam->slock);
+ return err;
+ }
+
+ spin_lock_init(&cam->slock);
+
dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
cam->vdev->num);
return 0;
@@ -876,17 +1643,10 @@ static int zr364xx_probe(struct usb_interface *intf,
static void zr364xx_disconnect(struct usb_interface *intf)
{
struct zr364xx_camera *cam = usb_get_intfdata(intf);
+ videobuf_mmap_free(&cam->vb_vidq);
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
- if (cam->vdev)
- video_unregister_device(cam->vdev);
- cam->vdev = NULL;
- kfree(cam->buffer);
- cam->buffer = NULL;
- vfree(cam->framebuf);
- cam->framebuf = NULL;
- kfree(cam);
- cam = NULL;
+ zr364xx_destroy(cam);
}