summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/Kconfig19
-rw-r--r--linux/drivers/media/video/Makefile4
-rw-r--r--linux/drivers/media/video/adv7170.c7
-rw-r--r--linux/drivers/media/video/adv7175.c5
-rw-r--r--linux/drivers/media/video/au0828/Kconfig10
-rw-r--r--linux/drivers/media/video/au0828/Makefile2
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.c127
-rw-r--r--linux/drivers/media/video/au0828/au0828-core.c34
-rw-r--r--linux/drivers/media/video/au0828/au0828-dvb.c2
-rw-r--r--linux/drivers/media/video/au0828/au0828-i2c.c72
-rw-r--r--linux/drivers/media/video/au0828/au0828-reg.h6
-rw-r--r--linux/drivers/media/video/au0828/au0828-video.c1718
-rw-r--r--linux/drivers/media/video/au0828/au0828.h181
-rw-r--r--linux/drivers/media/video/bt819.c18
-rw-r--r--linux/drivers/media/video/bt856.c2
-rw-r--r--linux/drivers/media/video/bt866.c2
-rw-r--r--linux/drivers/media/video/bt8xx/Kconfig1
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-cards.c392
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c107
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-i2c.c62
-rw-r--r--linux/drivers/media/video/bt8xx/bttv.h15
-rw-r--r--linux/drivers/media/video/bt8xx/bttvp.h11
-rw-r--r--linux/drivers/media/video/cafe_ccic.c438
-rw-r--r--linux/drivers/media/video/cpia2/cpia2_v4l.c1
-rw-r--r--linux/drivers/media/video/cs53l32a.c10
-rw-r--r--linux/drivers/media/video/cx18/Kconfig2
-rw-r--r--linux/drivers/media/video/cx18/cx18-audio.c1
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c42
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.h19
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c6
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c40
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c3
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c5
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.c108
-rw-r--r--linux/drivers/media/video/cx231xx/Kconfig35
-rw-r--r--linux/drivers/media/video/cx231xx/Makefile14
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-audio.c667
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-avcore.c2581
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-cards.c930
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h494
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-core.c1231
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-dvb.c560
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-i2c.c558
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-input.c263
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c795
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h231
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-reg.h1564
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-vbi.c711
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-vbi.h65
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-video.c2439
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx.h788
-rw-r--r--linux/drivers/media/video/cx23885/Kconfig15
-rw-r--r--linux/drivers/media/video/cx23885/Makefile4
-rw-r--r--linux/drivers/media/video/cx23885/cimax2.c484
-rw-r--r--linux/drivers/media/video/cx23885/cimax2.h47
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-417.c27
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c53
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-core.c26
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c110
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-reg.h2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c5
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h3
-rw-r--r--linux/drivers/media/video/cx23885/netup-eeprom.c117
-rw-r--r--linux/drivers/media/video/cx23885/netup-eeprom.h42
-rw-r--r--linux/drivers/media/video/cx23885/netup-init.c125
-rw-r--r--linux/drivers/media/video/cx23885/netup-init.h25
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-audio.c66
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.c173
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.h1
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-firmware.c11
-rw-r--r--linux/drivers/media/video/cx88/Kconfig2
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c6
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c4
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c53
-rw-r--r--linux/drivers/media/video/cx88/cx88-core.c4
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c16
-rw-r--r--linux/drivers/media/video/cx88/cx88-i2c.c8
-rw-r--r--linux/drivers/media/video/cx88/cx88-input.c31
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c11
-rw-r--r--linux/drivers/media/video/cx88/cx88.h10
-rw-r--r--linux/drivers/media/video/dabusb.c13
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c23
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c7
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c3
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c6
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-input.c24
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c7
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h5
-rw-r--r--linux/drivers/media/video/gspca/Kconfig9
-rw-r--r--linux/drivers/media/video/gspca/Makefile2
-rw-r--r--linux/drivers/media/video/gspca/conex.c54
-rw-r--r--linux/drivers/media/video/gspca/finepix.c421
-rw-r--r--linux/drivers/media/video/gspca/gspca.c20
-rw-r--r--linux/drivers/media/video/gspca/gspca.h1
-rw-r--r--linux/drivers/media/video/gspca/jpeg.h250
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c6
-rw-r--r--linux/drivers/media/video/gspca/mars.c79
-rw-r--r--linux/drivers/media/video/gspca/mr97310a.c22
-rw-r--r--linux/drivers/media/video/gspca/ov534.c839
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c129
-rw-r--r--linux/drivers/media/video/gspca/spca500.c55
-rw-r--r--linux/drivers/media/video/gspca/sq905.c104
-rw-r--r--linux/drivers/media/video/gspca/sq905c.c328
-rw-r--r--linux/drivers/media/video/gspca/stk014.c58
-rw-r--r--linux/drivers/media/video/gspca/sunplus.c55
-rw-r--r--linux/drivers/media/video/gspca/t613.c6
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c934
-rw-r--r--linux/drivers/media/video/gspca/zc3xx.c53
-rw-r--r--linux/drivers/media/video/hdpvr/Kconfig10
-rw-r--r--linux/drivers/media/video/hdpvr/Makefile9
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr-control.c201
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr-core.c466
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr-i2c.c145
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr-video.c1248
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr.h303
-rw-r--r--linux/drivers/media/video/indycam.c323
-rw-r--r--linux/drivers/media/video/indycam.h19
-rw-r--r--linux/drivers/media/video/ir-kbd-i2c.c24
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-vbi.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--linux/drivers/media/video/ks0127.c4
-rw-r--r--linux/drivers/media/video/meye.c45
-rw-r--r--linux/drivers/media/video/msp3400-driver.c118
-rw-r--r--linux/drivers/media/video/mt9m001.c162
-rw-r--r--linux/drivers/media/video/mt9m111.c56
-rw-r--r--linux/drivers/media/video/mt9t031.c90
-rw-r--r--linux/drivers/media/video/mt9v022.c207
-rw-r--r--linux/drivers/media/video/mx3_camera.c157
-rw-r--r--linux/drivers/media/video/mxb.c1
-rw-r--r--linux/drivers/media/video/omap24xxcam.c7
-rw-r--r--linux/drivers/media/video/ov7670.c566
-rw-r--r--linux/drivers/media/video/ov772x.c35
-rw-r--r--linux/drivers/media/video/ovcamchip/ovcamchip_core.c220
-rw-r--r--linux/drivers/media/video/ovcamchip/ovcamchip_priv.h7
-rw-r--r--linux/drivers/media/video/pvrusb2/Kconfig8
-rw-r--r--linux/drivers/media/video/pvrusb2/Makefile7
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-audio.c142
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-audio.h6
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c96
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h (renamed from linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h)21
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c245
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h4
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c5
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h12
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c102
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h34
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h38
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c626
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c117
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c337
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h51
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c417
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h57
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c121
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c4
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c214
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h7
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c134
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h4
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c2
-rw-r--r--linux/drivers/media/video/pxa_camera.c67
-rw-r--r--linux/drivers/media/video/saa6588.c26
-rw-r--r--linux/drivers/media/video/saa7110.c2
-rw-r--r--linux/drivers/media/video/saa7134/Kconfig12
-rw-r--r--linux/drivers/media/video/saa7134/saa6752hs.c2
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c199
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c7
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c72
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c3
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-ts.c15
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c5
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h9
-rw-r--r--linux/drivers/media/video/saa7146.h2
-rw-r--r--linux/drivers/media/video/saa7191.c508
-rw-r--r--linux/drivers/media/video/saa7191.h26
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c35
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_devtable.h2
-rw-r--r--linux/drivers/media/video/soc_camera.c135
-rw-r--r--linux/drivers/media/video/soc_camera_platform.c9
-rw-r--r--linux/drivers/media/video/stk-webcam.c24
-rw-r--r--linux/drivers/media/video/tlv320aic23b.c4
-rw-r--r--linux/drivers/media/video/tuner-core.c6
-rw-r--r--linux/drivers/media/video/tvaudio.c160
-rw-r--r--linux/drivers/media/video/tveeprom.c2
-rw-r--r--linux/drivers/media/video/tw9910.c45
-rw-r--r--linux/drivers/media/video/usbvideo/vicam.c2
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-core.c2
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-video.c22
-rw-r--r--linux/drivers/media/video/usbvision/usbvision.h2
-rw-r--r--linux/drivers/media/video/v4l2-common.c34
-rw-r--r--linux/drivers/media/video/v4l2-compat-ioctl32.c1
-rw-r--r--linux/drivers/media/video/v4l2-dev.c29
-rw-r--r--linux/drivers/media/video/v4l2-device.c15
-rw-r--r--linux/drivers/media/video/v4l2-ioctl.c189
-rw-r--r--linux/drivers/media/video/v4l2-subdev.c8
-rw-r--r--linux/drivers/media/video/vino.c1655
-rw-r--r--linux/drivers/media/video/vivi.c6
-rw-r--r--linux/drivers/media/video/vpx3220.c2
-rw-r--r--linux/drivers/media/video/w9966.c2
-rw-r--r--linux/drivers/media/video/w9968cf.c136
-rw-r--r--linux/drivers/media/video/w9968cf.h24
-rw-r--r--linux/drivers/media/video/zoran/Kconfig1
-rw-r--r--linux/drivers/media/video/zoran/zoran.h59
-rw-r--r--linux/drivers/media/video/zoran/zoran_card.c136
-rw-r--r--linux/drivers/media/video/zoran/zoran_device.c54
-rw-r--r--linux/drivers/media/video/zoran/zoran_device.h5
-rw-r--r--linux/drivers/media/video/zoran/zoran_driver.c1269
-rw-r--r--linux/drivers/media/video/zr364xx.c16
210 files changed, 27175 insertions, 7505 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index 6c26618b8..114bf04a6 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -582,7 +582,6 @@ config VIDEO_SAA5249
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
- select I2C_ALGO_SGI
select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
help
Say Y here to build in support for the Vino video input system found
@@ -708,13 +707,6 @@ config SOC_CAMERA_MT9M001
This driver supports MT9M001 cameras from Micron, monochrome
and colour models.
-config MT9M001_PCA9536_SWITCH
- bool "pca9536 datawidth switch for mt9m001"
- depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
- help
- Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
- extender to switch between 8 and 10 bit datawidth modes
-
config SOC_CAMERA_MT9M111
tristate "mt9m111 and mt9m112 support"
depends on SOC_CAMERA && I2C
@@ -734,13 +726,6 @@ config SOC_CAMERA_MT9V022
help
This driver supports MT9V022 cameras from Micron
-config MT9V022_PCA9536_SWITCH
- bool "pca9536 datawidth switch for mt9v022"
- depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
- help
- Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
- extender to switch between 8 and 10 bit datawidth modes
-
config SOC_CAMERA_TW9910
tristate "tw9910 support"
depends on SOC_CAMERA && I2C
@@ -804,8 +789,12 @@ source "drivers/media/video/gspca/Kconfig"
source "drivers/media/video/pvrusb2/Kconfig"
+source "drivers/media/video/hdpvr/Kconfig"
+
source "drivers/media/video/em28xx/Kconfig"
+source "drivers/media/video/cx231xx/Kconfig"
+
source "drivers/media/video/usbvision/Kconfig"
source "drivers/media/video/usbvideo/Kconfig"
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index 307490ebc..08765d874 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
@@ -68,6 +67,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
@@ -120,6 +120,8 @@ obj-$(CONFIG_USB_PWC) += pwc/
obj-$(CONFIG_USB_ZC0301) += zc0301/
obj-$(CONFIG_USB_GSPCA) += gspca/
+obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
+
obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
diff --git a/linux/drivers/media/video/adv7170.c b/linux/drivers/media/video/adv7170.c
index 87bc8ed46..04e6125f2 100644
--- a/linux/drivers/media/video/adv7170.c
+++ b/linux/drivers/media/video/adv7170.c
@@ -205,7 +205,7 @@ static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct adv7170 *encoder = to_adv7170(sd);
- v4l2_dbg(1, debug, sd, "set norm %llx\n", std);
+ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
if (std & V4L2_STD_NTSC) {
adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
@@ -220,10 +220,11 @@ static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
adv7170_write(sd, 0x07, TR0MODE | TR0RST);
adv7170_write(sd, 0x07, TR0MODE);
} else {
- v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", std);
+ v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
+ (unsigned long long)std);
return -EINVAL;
}
- v4l2_dbg(1, debug, sd, "switched to %llx\n", std);
+ v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
encoder->norm = std;
return 0;
}
diff --git a/linux/drivers/media/video/adv7175.c b/linux/drivers/media/video/adv7175.c
index dc036d2fa..c38f648f8 100644
--- a/linux/drivers/media/video/adv7175.c
+++ b/linux/drivers/media/video/adv7175.c
@@ -238,10 +238,11 @@ static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
adv7175_write(sd, 0x07, TR0MODE);
} else {
- v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", std);
+ v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
+ (unsigned long long)std);
return -EINVAL;
}
- v4l2_dbg(1, debug, sd, "switched to %llx\n", std);
+ v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
encoder->norm = std;
return 0;
}
diff --git a/linux/drivers/media/video/au0828/Kconfig b/linux/drivers/media/video/au0828/Kconfig
index 018f72b8e..05cdf494d 100644
--- a/linux/drivers/media/video/au0828/Kconfig
+++ b/linux/drivers/media/video/au0828/Kconfig
@@ -1,13 +1,13 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
- depends on I2C && INPUT && DVB_CORE && USB
+ depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
select I2C_ALGOBIT
select VIDEO_TVEEPROM
- select DVB_AU8522 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select DVB_AU8522 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
---help---
This is a video4linux driver for Auvitek's USB device.
diff --git a/linux/drivers/media/video/au0828/Makefile b/linux/drivers/media/video/au0828/Makefile
index cd2c58281..4d2623158 100644
--- a/linux/drivers/media/video/au0828/Makefile
+++ b/linux/drivers/media/video/au0828/Makefile
@@ -1,4 +1,4 @@
-au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c
index d60123b41..1aabaa7e5 100644
--- a/linux/drivers/media/video/au0828/au0828-cards.c
+++ b/linux/drivers/media/video/au0828/au0828-cards.c
@@ -21,25 +21,89 @@
#include "au0828.h"
#include "au0828-cards.h"
+#include "au8522.h"
+#include "media/tuner.h"
+#include "media/v4l2-common.h"
+
+void hvr950q_cs5340_audio(void *priv, int enable)
+{
+ /* Because the HVR-950q shares an i2s bus between the cs5340 and the
+ au8522, we need to hold cs5340 in reset when using the au8522 */
+ struct au0828_dev *dev = priv;
+ if (enable == 1)
+ au0828_set(dev, REG_000, 0x10);
+ else
+ au0828_clear(dev, REG_000, 0x10);
+}
struct au0828_board au0828_boards[] = {
[AU0828_BOARD_UNKNOWN] = {
.name = "Unknown board",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
},
[AU0828_BOARD_HAUPPAUGE_HVR850] = {
.name = "Hauppauge HVR850",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .input = {
+ {
+ .type = AU0828_VMUX_TELEVISION,
+ .vmux = AU8522_COMPOSITE_CH4_SIF,
+ .amux = AU8522_AUDIO_SIF,
+ },
+ {
+ .type = AU0828_VMUX_COMPOSITE,
+ .vmux = AU8522_COMPOSITE_CH1,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ {
+ .type = AU0828_VMUX_SVIDEO,
+ .vmux = AU8522_SVIDEO_CH13,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ },
},
[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
.name = "Hauppauge HVR950Q",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .input = {
+ {
+ .type = AU0828_VMUX_TELEVISION,
+ .vmux = AU8522_COMPOSITE_CH4_SIF,
+ .amux = AU8522_AUDIO_SIF,
+ },
+ {
+ .type = AU0828_VMUX_COMPOSITE,
+ .vmux = AU8522_COMPOSITE_CH1,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ {
+ .type = AU0828_VMUX_SVIDEO,
+ .vmux = AU8522_SVIDEO_CH13,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ },
},
[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
.name = "Hauppauge HVR950Q rev xxF8",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
},
[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
.name = "DViCO FusionHDTV USB",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
},
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
.name = "Hauppauge Woodbury",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
},
};
@@ -52,7 +116,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
dprintk(1, "%s()\n", __func__);
- switch (dev->board) {
+ switch (dev->boardnr) {
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
@@ -81,17 +145,18 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
struct tveeprom tv;
tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+ dev->board.tuner_type = tv.tuner_type;
/* Make sure we support the board model */
switch (tv.model) {
case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
- case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
- case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
- case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
- case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
- case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
- case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
- case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+ case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
break;
default:
@@ -107,15 +172,21 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
void au0828_card_setup(struct au0828_dev *dev)
{
static u8 eeprom[256];
+ struct tuner_setup tun_setup;
+ struct v4l2_subdev *sd;
+ unsigned int mode_mask = T_ANALOG_TV |
+ T_DIGITAL_TV;
dprintk(1, "%s()\n", __func__);
+ memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
+
if (dev->i2c_rc == 0) {
dev->i2c_client.addr = 0xa0 >> 1;
tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
}
- switch (dev->board) {
+ switch (dev->boardnr) {
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
@@ -124,6 +195,32 @@ void au0828_card_setup(struct au0828_dev *dev)
hauppauge_eeprom(dev, eeprom+0xa0);
break;
}
+
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+ /* Load the analog demodulator driver (note this would need to
+ be abstracted out if we ever need to support a different
+ demod) */
+ sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "au8522", "au8522",
+ 0x8e >> 1);
+ if (sd == NULL)
+ printk(KERN_ERR "analog subdev registration failed\n");
+ }
+
+ /* Setup tuners */
+ if (dev->board.tuner_type != TUNER_ABSENT) {
+ /* Load the tuner module, which does the attach */
+ sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "tuner", "tuner",
+ dev->board.tuner_addr);
+ if (sd == NULL)
+ printk(KERN_ERR "tuner subdev registration fail\n");
+
+ tun_setup.mode_mask = mode_mask;
+ tun_setup.type = dev->board.tuner_type;
+ tun_setup.addr = dev->board.tuner_addr;
+ tun_setup.tuner_callback = au0828_tuner_callback;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
+ &tun_setup);
+ }
}
/*
@@ -135,7 +232,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
{
dprintk(1, "%s()\n", __func__);
- switch (dev->board) {
+ switch (dev->boardnr) {
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
@@ -144,21 +241,23 @@ void au0828_gpio_setup(struct au0828_dev *dev)
* 4 - CS5340
* 5 - AU8522 Demodulator
* 6 - eeprom W/P
+ * 7 - power supply
* 9 - XC5000 Tuner
*/
/* Into reset */
au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_002, 0x88 | 0x20);
+ au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
au0828_write(dev, REG_001, 0x0);
au0828_write(dev, REG_000, 0x0);
msleep(100);
- /* Out of reset */
+ /* Out of reset (leave the cs5340 in reset until needed) */
au0828_write(dev, REG_003, 0x02);
au0828_write(dev, REG_001, 0x02);
- au0828_write(dev, REG_002, 0x88 | 0x20);
- au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
+ au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+ au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+
msleep(250);
break;
case AU0828_BOARD_DVICO_FUSIONHDTV7:
diff --git a/linux/drivers/media/video/au0828/au0828-core.c b/linux/drivers/media/video/au0828/au0828-core.c
index 05e38f41c..ffe1bf019 100644
--- a/linux/drivers/media/video/au0828/au0828-core.c
+++ b/linux/drivers/media/video/au0828/au0828-core.c
@@ -37,6 +37,8 @@ int au0828_debug;
module_param_named(debug, au0828_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
+static atomic_t au0828_instance = ATOMIC_INIT(0);
+
#define _AU0828_BULKPIPE 0x03
#define _BULKPIPESIZE 0xffff
@@ -52,13 +54,13 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
{
recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
- dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]);
+ dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]);
return dev->ctrlmsg[0];
}
u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
{
- dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val);
+ dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
dev->ctrlmsg, 0);
}
@@ -147,9 +149,14 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
/* Digital TV */
au0828_dvb_unregister(dev);
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+ au0828_analog_unregister(dev);
+
/* I2C */
au0828_i2c_unregister(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
usb_set_intfdata(interface, NULL);
mutex_lock(&dev->mutex);
@@ -163,7 +170,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
static int au0828_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- int ifnum;
+ int ifnum, retval, i;
struct au0828_dev *dev;
struct usb_device *usbdev = interface_to_usbdev(interface);
@@ -186,10 +193,22 @@ static int au0828_usb_probe(struct usb_interface *interface,
mutex_init(&dev->mutex);
mutex_init(&dev->dvb.lock);
dev->usbdev = usbdev;
- dev->board = id->driver_info;
+ dev->boardnr = id->driver_info;
usb_set_intfdata(interface, dev);
+ /* Create the v4l2_device */
+ i = atomic_inc_return(&au0828_instance) - 1;
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d",
+ "au0828", i);
+ retval = v4l2_device_register(&dev->usbdev->dev, &dev->v4l2_dev);
+ if (retval) {
+ printk(KERN_ERR "%s() v4l2_device_register failed\n",
+ __func__);
+ kfree(dev);
+ return -EIO;
+ }
+
/* Power Up the bridge */
au0828_write(dev, REG_600, 1 << 4);
@@ -202,12 +221,15 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Setup */
au0828_card_setup(dev);
+ /* Analog TV */
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+ au0828_analog_register(dev, interface);
+
/* Digital TV */
au0828_dvb_register(dev);
printk(KERN_INFO "Registered device AU0828 [%s]\n",
- au0828_boards[dev->board].name == NULL ? "Unset" :
- au0828_boards[dev->board].name);
+ dev->board.name == NULL ? "Unset" : dev->board.name);
return 0;
}
diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c
index 9966f83d5..104f15cc3 100644
--- a/linux/drivers/media/video/au0828/au0828-dvb.c
+++ b/linux/drivers/media/video/au0828/au0828-dvb.c
@@ -383,7 +383,7 @@ int au0828_dvb_register(struct au0828_dev *dev)
dprintk(1, "%s()\n", __func__);
/* init frontend */
- switch (dev->board) {
+ switch (dev->boardnr) {
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
dvb->frontend = dvb_attach(au8522_attach,
diff --git a/linux/drivers/media/video/au0828/au0828-i2c.c b/linux/drivers/media/video/au0828/au0828-i2c.c
index d8cef6ccc..eb63166f6 100644
--- a/linux/drivers/media/video/au0828/au0828-i2c.c
+++ b/linux/drivers/media/video/au0828/au0828-i2c.c
@@ -141,13 +141,39 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
dprintk(4, "%s()\n", __func__);
au0828_write(dev, REG_2FF, 0x01);
- au0828_write(dev, REG_202, 0x07);
+
+ /* FIXME: There is a problem with i2c communications with xc5000 that
+ requires us to slow down the i2c clock until we have a better
+ strategy (such as using the secondary i2c bus to do firmware
+ loading */
+ if ((msg->addr << 1) == 0xc2)
+ au0828_write(dev, REG_202, 0x40);
+ else
+ au0828_write(dev, REG_202, 0x07);
/* Hardware needs 8 bit addresses */
au0828_write(dev, REG_203, msg->addr << 1);
dprintk(4, "SEND: %02x\n", msg->addr);
+ /* Deal with i2c_scan */
+ if (msg->len == 0) {
+ /* The analog tuner detection code makes use of the SMBUS_QUICK
+ message (which involves a zero length i2c write). To avoid
+ checking the status register when we didn't strobe out any
+ actual bytes to the bus, just do a read check. This is
+ consistent with how I saw i2c device checking done in the
+ USB trace of the Windows driver */
+ au0828_write(dev, REG_200, 0x20);
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ if (i2c_wait_read_ack(i2c_adap))
+ return -EIO;
+
+ return 0;
+ }
+
for (i = 0; i < msg->len;) {
dprintk(4, " %02x\n", msg->buf[i]);
@@ -192,7 +218,15 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
dprintk(4, "%s()\n", __func__);
au0828_write(dev, REG_2FF, 0x01);
- au0828_write(dev, REG_202, 0x07);
+
+ /* FIXME: There is a problem with i2c communications with xc5000 that
+ requires us to slow down the i2c clock until we have a better
+ strategy (such as using the secondary i2c bus to do firmware
+ loading */
+ if ((msg->addr << 1) == 0xc2)
+ au0828_write(dev, REG_202, 0x40);
+ else
+ au0828_write(dev, REG_202, 0x07);
/* Hardware needs 8 bit addresses */
au0828_write(dev, REG_203, msg->addr << 1);
@@ -266,33 +300,6 @@ err:
return retval;
}
-static int attach_inform(struct i2c_client *client)
-{
- dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
- client->driver->driver.name, client->addr, client->name);
-
- if (!client->driver->command)
- return 0;
-
- return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
- dprintk(1, "i2c detach [client=%s]\n", client->name);
-
- return 0;
-}
-
-void au0828_call_i2c_clients(struct au0828_dev *dev,
- unsigned int cmd, void *arg)
-{
- if (dev->i2c_rc != 0)
- return;
-
- i2c_clients_command(&dev->i2c_adap, cmd, arg);
-}
-
static u32 au0828_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
@@ -313,9 +320,6 @@ static struct i2c_adapter au0828_i2c_adap_template = {
.owner = THIS_MODULE,
.id = I2C_HW_B_AU0828,
.algo = &au0828_i2c_algo_template,
- .class = I2C_CLASS_TV_ANALOG,
- .client_register = attach_inform,
- .client_unregister = detach_inform,
};
static struct i2c_client au0828_i2c_client_template = {
@@ -360,9 +364,9 @@ int au0828_i2c_register(struct au0828_dev *dev)
strlcpy(dev->i2c_adap.name, DRIVER_NAME,
sizeof(dev->i2c_adap.name));
- dev->i2c_algo.data = dev;
+ dev->i2c_adap.algo = &dev->i2c_algo;
dev->i2c_adap.algo_data = dev;
- i2c_set_adapdata(&dev->i2c_adap, dev);
+ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
i2c_add_adapter(&dev->i2c_adap);
dev->i2c_client.adapter = &dev->i2c_adap;
diff --git a/linux/drivers/media/video/au0828/au0828-reg.h b/linux/drivers/media/video/au0828/au0828-reg.h
index 1e87fa0c6..b15e4a3b6 100644
--- a/linux/drivers/media/video/au0828/au0828-reg.h
+++ b/linux/drivers/media/video/au0828/au0828-reg.h
@@ -27,6 +27,9 @@
#define REG_002 0x002
#define REG_003 0x003
+#define AU0828_SENSORCTRL_100 0x100
+#define AU0828_SENSORCTRL_VBI_103 0x103
+
#define REG_200 0x200
#define REG_201 0x201
#define REG_202 0x202
@@ -35,4 +38,7 @@
#define REG_209 0x209
#define REG_2FF 0x2ff
+/* Audio registers */
+#define AU0828_AUDIOCTRL_50C 0x50C
+
#define REG_600 0x600
diff --git a/linux/drivers/media/video/au0828/au0828-video.c b/linux/drivers/media/video/au0828/au0828-video.c
new file mode 100644
index 000000000..5eac5cde5
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-video.c
@@ -0,0 +1,1718 @@
+/*
+ * Auvitek AU0828 USB Bridge (Analog video support)
+ *
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
+ * Copyright (C) 2005-2008 Auvitek International, Ltd.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/* Developer Notes:
+ *
+ * VBI support is not yet working
+ * The hardware scaler supported is unimplemented
+ * AC97 audio support is unimplemented (only i2s audio mode)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/tuner.h>
+#include "compat.h"
+#include "au0828.h"
+#include "au0828-reg.h"
+
+static LIST_HEAD(au0828_devlist);
+static DEFINE_MUTEX(au0828_sysfs_lock);
+
+#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define au0828_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
+ printk(KERN_INFO "au0828 %s :"fmt, \
+ __func__ , ##arg); \
+ } \
+ } while (0)
+
+static inline void print_err_status(struct au0828_dev *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ au0828_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ au0828_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+static int check_dev(struct au0828_dev *dev)
+{
+ if (dev->dev_state & DEV_DISCONNECTED) {
+ printk(KERN_INFO "v4l2 ioctl: device not present\n");
+ return -ENODEV;
+ }
+
+ if (dev->dev_state & DEV_MISCONFIGURED) {
+ printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
+ "close and open it again\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * IRQ callback, called by URB callback
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void au0828_irq_callback(struct urb *urb, struct pt_regs *regs)
+#else
+static void au0828_irq_callback(struct urb *urb)
+#endif
+{
+ struct au0828_dmaqueue *dma_q = urb->context;
+ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+ int rc, i;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ au0828_isocdbg("au0828_irq_callback called: status kill\n");
+ return;
+ default: /* unknown error */
+ au0828_isocdbg("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ /* Copy data from URB */
+ spin_lock(&dev->slock);
+ rc = dev->isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock(&dev->slock);
+
+ /* Reset urb buffers */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ urb->status = 0;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ au0828_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
+ }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void au0828_uninit_isoc(struct au0828_dev *dev)
+{
+ struct urb *urb;
+ int i;
+
+ au0828_isocdbg("au0828: called au0828_uninit_isoc\n");
+
+ dev->isoc_ctl.nfields = -1;
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = dev->isoc_ctl.urb[i];
+ if (urb) {
+ if (!irqs_disabled())
+ usb_kill_urb(urb);
+ else
+ usb_unlink_urb(urb);
+
+ if (dev->isoc_ctl.transfer_buffer[i]) {
+ usb_buffer_free(dev->usbdev,
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
+ }
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
+ dev->isoc_ctl.num_bufs = 0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb))
+{
+ struct au0828_dmaqueue *dma_q = &dev->vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int j, k;
+ int rc;
+
+ au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
+
+ /* De-allocates all pending stuff */
+ au0828_uninit_isoc(dev);
+
+ dev->isoc_ctl.isoc_copy = isoc_copy;
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ au0828_isocdbg("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!dev->isoc_ctl.transfer_buffer) {
+ au0828_isocdbg("cannot allocate memory for usb transfer\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.max_pkt_size = max_pkt_size;
+ dev->isoc_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i);
+ au0828_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ dev->isoc_ctl.urb[i] = urb;
+
+ dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->usbdev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ printk("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
+ au0828_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ pipe = usb_rcvisocpipe(dev->usbdev,
+ dev->isoc_in_endpointaddr),
+
+ usb_fill_int_urb(urb, dev->usbdev, pipe,
+ dev->isoc_ctl.transfer_buffer[i], sb_size,
+ au0828_irq_callback, dma_q, 1);
+
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+ k = 0;
+ for (j = 0; j < max_packets; j++) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ dev->isoc_ctl.max_pkt_size;
+ k += dev->isoc_ctl.max_pkt_size;
+ }
+ }
+
+ init_waitqueue_head(&dma_q->wq);
+
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+ if (rc) {
+ au0828_isocdbg("submit of urb %i failed (error=%i)\n",
+ i, rc);
+ au0828_uninit_isoc(dev);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void au0828_copy_video(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy, remain;
+ int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ startread = p;
+ remain = len;
+
+ /* Interlaces frame */
+ if (buf->top_field)
+ fieldstart = outp;
+ else
+ fieldstart = outp + bytesperline;
+
+ linesdone = dma_q->pos / bytesperline;
+ currlinedone = dma_q->pos % bytesperline;
+ offset = linesdone * bytesperline * 2 + currlinedone;
+ startwrite = fieldstart + offset;
+ lencopy = bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ lencopy = remain;
+ }
+ if (lencopy <= 0)
+ return;
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + bytesperline;
+ startread += lencopy;
+ if (bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = bytesperline;
+
+ if ((char *)startwrite + lencopy > (char *)outp +
+ buf->vb.size) {
+ au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size -
+ (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ break;
+
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+ }
+
+ if (offset > 1440) {
+ /* We have enough data to check for greenscreen */
+ if (outp[0] < 0x60 && outp[1440] < 0x60)
+ dev->greenscreen_detected = 1;
+ }
+
+ dma_q->pos += len;
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer **buf)
+{
+ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+
+ if (list_empty(&dma_q->active)) {
+ au0828_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+ dev->isoc_ctl.buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
+{
+ struct au0828_buffer *buf;
+ struct au0828_dmaqueue *dma_q = urb->context;
+ unsigned char *outp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+ unsigned char fbyte;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->dev_state & DEV_DISCONNECTED) ||
+ (dev->dev_state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ if (urb->iso_frame_desc[i].actual_length <= 0)
+ continue;
+
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ au0828_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ fbyte = p[0];
+ len = urb->iso_frame_desc[i].actual_length - 4;
+ p += 4;
+
+ if (fbyte & 0x80) {
+ len -= 4;
+ p += 4;
+ au0828_isocdbg("Video frame %s\n",
+ (fbyte & 0x40) ? "odd" : "even");
+ if (!(fbyte & 0x40)) {
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+ }
+
+ if (buf != NULL) {
+ if (fbyte & 0x40)
+ buf->top_field = 1;
+ else
+ buf->top_field = 0;
+ }
+
+ dma_q->pos = 0;
+ }
+ if (buf != NULL)
+ au0828_copy_video(dev, dma_q, buf, p, outp, len);
+ }
+ return rc;
+}
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct au0828_fh *fh = vq->priv_data;
+ *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+ if (0 == *count)
+ *count = AU0828_DEF_BUF;
+
+ if (*count < AU0828_MIN_BUF)
+ *count = AU0828_MIN_BUF;
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf == buf)
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ 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 au0828_fh *fh = vq->priv_data;
+ struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+ struct au0828_dev *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0) {
+ printk(KERN_INFO "videobuf_iolock failed\n");
+ goto fail;
+ }
+ }
+
+ if (!dev->isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
+ AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
+ au0828_isoc_copy);
+ if (rc < 0) {
+ printk(KERN_INFO "au0828_init_isoc failed\n");
+ goto fail;
+ }
+ }
+
+ 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 au0828_buffer *buf = container_of(vb,
+ struct au0828_buffer,
+ vb);
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ struct au0828_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct au0828_buffer *buf = container_of(vb,
+ struct au0828_buffer,
+ vb);
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops au0828_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+ V4L2 interface
+ ------------------------------------------------------------------*/
+
+static int au0828_i2s_init(struct au0828_dev *dev)
+{
+ /* Enable i2s mode */
+ au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01);
+ return 0;
+}
+
+/*
+ * Auvitek au0828 analog stream enable
+ * Please set interface0 to AS5 before enable the stream
+ */
+int au0828_analog_stream_enable(struct au0828_dev *d)
+{
+ dprintk(1, "au0828_analog_stream_enable called\n");
+ au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
+ au0828_writereg(d, 0x106, 0x00);
+ /* set x position */
+ au0828_writereg(d, 0x110, 0x00);
+ au0828_writereg(d, 0x111, 0x00);
+ au0828_writereg(d, 0x114, 0xa0);
+ au0828_writereg(d, 0x115, 0x05);
+ /* set y position */
+ au0828_writereg(d, 0x112, 0x02);
+ au0828_writereg(d, 0x113, 0x00);
+ au0828_writereg(d, 0x116, 0xf2);
+ au0828_writereg(d, 0x117, 0x00);
+ au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
+
+ return 0;
+}
+
+int au0828_analog_stream_disable(struct au0828_dev *d)
+{
+ dprintk(1, "au0828_analog_stream_disable called\n");
+ au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
+ return 0;
+}
+
+void au0828_analog_stream_reset(struct au0828_dev *dev)
+{
+ dprintk(1, "au0828_analog_stream_reset called\n");
+ au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0);
+ mdelay(30);
+ au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3);
+}
+
+/*
+ * Some operations needs to stop current streaming
+ */
+static int au0828_stream_interrupt(struct au0828_dev *dev)
+{
+ int ret = 0;
+
+ dev->stream_state = STREAM_INTERRUPT;
+ if (dev->dev_state == DEV_DISCONNECTED)
+ return -ENODEV;
+ else if (ret) {
+ dev->dev_state = DEV_MISCONFIGURED;
+ dprintk(1, "%s device is misconfigured!\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * au0828_release_resources
+ * unregister v4l2 devices
+ */
+void au0828_analog_unregister(struct au0828_dev *dev)
+{
+ dprintk(1, "au0828_release_resources called\n");
+ mutex_lock(&au0828_sysfs_lock);
+
+ if (dev->vdev) {
+ list_del(&dev->au0828list);
+ video_unregister_device(dev->vdev);
+ }
+ if (dev->vbi_dev)
+ video_unregister_device(dev->vbi_dev);
+
+ mutex_unlock(&au0828_sysfs_lock);
+}
+
+
+/* Usage lock check functions */
+static int res_get(struct au0828_fh *fh)
+{
+ struct au0828_dev *dev = fh->dev;
+ int rc = 0;
+
+ /* This instance already has stream_on */
+ if (fh->stream_on)
+ return rc;
+
+ if (dev->stream_on)
+ return -EBUSY;
+
+ dev->stream_on = 1;
+ fh->stream_on = 1;
+ return rc;
+}
+
+static int res_check(struct au0828_fh *fh)
+{
+ return fh->stream_on;
+}
+
+static void res_free(struct au0828_fh *fh)
+{
+ struct au0828_dev *dev = fh->dev;
+
+ fh->stream_on = 0;
+ dev->stream_on = 0;
+}
+
+static int au0828_v4l2_open(struct file *filp)
+{
+ int minor = video_devdata(filp)->minor;
+ int ret = 0;
+ struct au0828_dev *h, *dev = NULL;
+ struct au0828_fh *fh;
+ int type = 0;
+ struct list_head *list;
+
+ list_for_each(list, &au0828_devlist) {
+ h = list_entry(list, struct au0828_dev, au0828list);
+ if (h->vdev->minor == minor) {
+ dev = h;
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ }
+#ifdef VBI_IS_WORKING
+ if (h->vbi_dev->minor == minor) {
+ dev = h;
+ type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ }
+#endif
+ }
+
+ if (NULL == dev)
+ return -ENODEV;
+
+ fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
+ if (NULL == fh) {
+ dprintk(1, "Failed allocate au0828_fh struct!\n");
+ return -ENOMEM;
+ }
+
+ fh->type = type;
+ fh->dev = dev;
+ filp->private_data = fh;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ /* set au0828 interface0 to AS5 here again */
+ ret = usb_set_interface(dev->usbdev, 0, 5);
+ if (ret < 0) {
+ printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+ return -EBUSY;
+ }
+ dev->width = NTSC_STD_W;
+ dev->height = NTSC_STD_H;
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->width * dev->height;
+ dev->bytesperline = dev->width * 2;
+
+ au0828_analog_stream_enable(dev);
+ au0828_analog_stream_reset(dev);
+
+ /* If we were doing ac97 instead of i2s, it would go here...*/
+ au0828_i2s_init(dev);
+
+ dev->stream_state = STREAM_OFF;
+ dev->dev_state |= DEV_INITIALIZED;
+ }
+
+ dev->users++;
+
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
+ NULL, &dev->slock, fh->type,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct au0828_buffer), fh);
+
+ return ret;
+}
+
+static int au0828_v4l2_close(struct file *filp)
+{
+ int ret;
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+
+ mutex_lock(&dev->lock);
+ if (res_check(fh))
+ res_free(fh);
+
+ if (dev->users == 1) {
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ if (dev->dev_state & DEV_DISCONNECTED) {
+ au0828_analog_unregister(dev);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return 0;
+ }
+
+ au0828_analog_stream_disable(dev);
+
+ au0828_uninit_isoc(dev);
+
+ /* When close the device, set the usb intf0 into alt0 to free
+ USB bandwidth */
+ ret = usb_set_interface(dev->usbdev, 0, 0);
+ if (ret < 0)
+ printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
+ }
+
+ kfree(fh);
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return rc;
+
+ return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+ return 0;
+}
+
+static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
+{
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return POLLERR;
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+}
+
+static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return rc;
+
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+ dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ rc);
+
+ return rc;
+}
+
+static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
+ struct v4l2_format *format)
+{
+ int ret;
+ int width = format->fmt.pix.width;
+ int height = format->fmt.pix.height;
+ unsigned int maxwidth, maxheight;
+
+ maxwidth = 720;
+ maxheight = 480;
+
+#ifdef VBI_IS_WORKING
+ if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ dprintk(1, "VBI format set: to be supported!\n");
+ return 0;
+ }
+ if (format->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ return 0;
+#endif
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* If they are demanding a format other than the one we support,
+ bail out (tvtime asks for UYVY and then retries with YUYV) */
+ if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
+ return -EINVAL;
+
+ /* format->fmt.pix.width only support 720 and height 480 */
+ if (width != 720)
+ width = 720;
+ if (height != 480)
+ height = 480;
+
+ format->fmt.pix.width = width;
+ format->fmt.pix.height = height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ format->fmt.pix.bytesperline = width * 2;
+ format->fmt.pix.sizeimage = width * height * 2;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ if (cmd == VIDIOC_TRY_FMT)
+ return 0;
+
+ /* maybe set new image format, driver current only support 720*480 */
+ dev->width = width;
+ dev->height = height;
+ dev->frame_size = width * height * 2;
+ dev->field_size = width * height;
+ dev->bytesperline = width * 2;
+
+ if (dev->stream_state == STREAM_ON) {
+ dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
+ ret = au0828_stream_interrupt(dev);
+ if (ret != 0) {
+ dprintk(1, "error interrupting video stream!\n");
+ return ret;
+ }
+ }
+
+ /* set au0828 interface0 to AS5 here again */
+ ret = usb_set_interface(dev->usbdev, 0, 5);
+ if (ret < 0) {
+ printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+ return -EBUSY;
+ }
+
+ au0828_analog_stream_enable(dev);
+
+ return 0;
+}
+
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
+ if (qc->type)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ strlcpy(cap->driver, "au0828", sizeof(cap->driver));
+ strlcpy(cap->card, dev->board.name, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+
+ cap->version = AU0828_VERSION_CODE;
+
+ /*set the device capabilities */
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+#ifdef VBI_IS_WORKING
+ V4L2_CAP_VBI_CAPTURE |
+#endif
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index)
+ return -EINVAL;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(f->description, "Packed YUV2");
+
+ f->flags = 0;
+ f->pixelformat = V4L2_PIX_FMT_UYVY;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ f->fmt.pix.bytesperline = dev->bytesperline;
+ f->fmt.pix.sizeimage = dev->frame_size;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ printk(KERN_INFO "%s queue busy\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
+
+ if (dev->stream_on && !fh->stream_on) {
+ printk(KERN_INFO "%s device in use by another fh\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
+
+ return au0828_set_format(dev, VIDIOC_S_FMT, f);
+out:
+ return rc;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ /* FIXME: when we support something other than NTSC, we are going to
+ have to make the au0828 bridge adjust the size of its capture
+ buffer, which is currently hardcoded at 720x480 */
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_std, *norm);
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ unsigned int tmp;
+
+ static const char *inames[] = {
+ [AU0828_VMUX_UNDEFINED] = "Undefined",
+ [AU0828_VMUX_COMPOSITE] = "Composite",
+ [AU0828_VMUX_SVIDEO] = "S-Video",
+ [AU0828_VMUX_CABLE] = "Cable TV",
+ [AU0828_VMUX_TELEVISION] = "Television",
+ [AU0828_VMUX_DVB] = "DVB",
+ [AU0828_VMUX_DEBUG] = "tv debug"
+ };
+
+ tmp = input->index;
+
+ if (tmp > AU0828_MAX_INPUT)
+ return -EINVAL;
+ if (AUVI_INPUT(tmp).type == 0)
+ return -EINVAL;
+
+ input->index = tmp;
+ strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
+ if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
+ (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+ input->type |= V4L2_INPUT_TYPE_TUNER;
+ else
+ input->type |= V4L2_INPUT_TYPE_CAMERA;
+
+ input->std = dev->vdev->tvnorms;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ *i = dev->ctrl_input;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int i;
+ struct v4l2_routing route;
+
+ dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
+ index);
+ if (index >= AU0828_MAX_INPUT)
+ return -EINVAL;
+ if (AUVI_INPUT(index).type == 0)
+ return -EINVAL;
+ dev->ctrl_input = index;
+
+ switch (AUVI_INPUT(index).type) {
+ case AU0828_VMUX_SVIDEO:
+ dev->input_type = AU0828_VMUX_SVIDEO;
+ break;
+ case AU0828_VMUX_COMPOSITE:
+ dev->input_type = AU0828_VMUX_COMPOSITE;
+ break;
+ case AU0828_VMUX_TELEVISION:
+ dev->input_type = AU0828_VMUX_TELEVISION;
+ break;
+ default:
+ dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+ AUVI_INPUT(index).type);
+ break;
+ }
+
+ route.input = AUVI_INPUT(index).vmux;
+ route.output = 0;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, &route);
+
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ int enable = 0;
+ if (AUVI_INPUT(i).audio_setup == NULL)
+ continue;
+
+ if (i == index)
+ enable = 1;
+ else
+ enable = 0;
+ if (enable) {
+ (AUVI_INPUT(i).audio_setup)(dev, enable);
+ } else {
+ /* Make sure we leave it turned on if some
+ other input is routed to this callback */
+ if ((AUVI_INPUT(i).audio_setup) !=
+ ((AUVI_INPUT(index).audio_setup))) {
+ (AUVI_INPUT(i).audio_setup)(dev, enable);
+ }
+ }
+ }
+
+ route.input = AUVI_INPUT(index).amux;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, &route);
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ unsigned int index = a->index;
+
+ if (a->index > 1)
+ return -EINVAL;
+
+ index = dev->ctrl_ainput;
+ if (index == 0)
+ strcpy(a->name, "Television");
+ else
+ strcpy(a->name, "Line in");
+
+ a->capability = V4L2_AUDCAP_STEREO;
+ a->index = index;
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ if (a->index != dev->ctrl_ainput)
+ return -EINVAL;
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+ return 0;
+
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (t->index != 0)
+ return -EINVAL;
+
+ strcpy(t->name, "Auvitek tuner");
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (t->index != 0)
+ return -EINVAL;
+
+ t->type = V4L2_TUNER_ANALOG_TV;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+ dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
+ t->afc);
+ return 0;
+
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ freq->frequency = dev->ctrl_freq;
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (freq->tuner != 0)
+ return -EINVAL;
+ if (freq->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+
+ dev->ctrl_freq = freq->frequency;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
+
+ au0828_analog_stream_reset(dev);
+
+ return 0;
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+
+ if (v4l2_chip_match_host(&chip->match)) {
+ chip->ident = V4L2_IDENT_AU0828;
+ return 0;
+ }
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
+ if (chip->ident == V4L2_IDENT_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cc)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+
+ cc->defrect = cc->bounds;
+
+ cc->pixelaspect.numerator = 54;
+ cc->pixelaspect.denominator = 59;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ au0828_analog_stream_enable(dev);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
+ }
+
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+
+ if (likely(rc >= 0))
+ rc = videobuf_streamon(&fh->vb_vidq);
+ mutex_unlock(&dev->lock);
+
+ return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int i;
+ int ret;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (type != fh->type)
+ return -EINVAL;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+ ret = au0828_stream_interrupt(dev);
+ if (ret != 0)
+ return ret;
+ }
+
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ if (AUVI_INPUT(i).audio_setup == NULL)
+ continue;
+ (AUVI_INPUT(i).audio_setup)(dev, 0);
+ }
+
+ mutex_lock(&dev->lock);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ /* Workaround for a bug in the au0828 hardware design that sometimes
+ results in the colorspace being inverted */
+ if (dev->greenscreen_detected == 1) {
+ dprintk(1, "Detected green frame. Resetting stream...\n");
+ au0828_analog_stream_reset(dev);
+ dev->greenscreen_detected = 0;
+ }
+
+ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct au0828_fh *fh = priv;
+
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+static struct v4l2_file_operations au0828_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = au0828_v4l2_open,
+ .release = au0828_v4l2_close,
+ .read = au0828_v4l2_read,
+ .poll = au0828_v4l2_poll,
+ .mmap = au0828_v4l2_mmap,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+#ifdef VBI_IS_WORKING
+ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
+#endif
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_cropcap = vidioc_cropcap,
+#ifdef VBI_IS_WORKING
+ .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
+ .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+ .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+#endif
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+};
+
+static const struct video_device au0828_video_template = {
+ .fops = &au0828_v4l_fops,
+ .release = video_device_release,
+ .ioctl_ops = &video_ioctl_ops,
+ .minor = -1,
+ .tvnorms = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+/**************************************************************************/
+
+int au0828_analog_register(struct au0828_dev *dev,
+ struct usb_interface *interface)
+{
+ int retval = -ENOMEM;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+
+ dprintk(1, "au0828_analog_register called!\n");
+
+ /* set au0828 usb interface0 to as5 */
+ retval = usb_set_interface(dev->usbdev,
+ interface->cur_altsetting->desc.bInterfaceNumber, 5);
+ if (retval != 0) {
+ printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+ return retval;
+ }
+
+ /* Figure out which endpoint has the isoc interface */
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_ISOC)) {
+
+ /* we find our isoc in endpoint */
+ u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
+ dev->max_pkt_size = (tmp & 0x07ff) *
+ (((tmp & 0x1800) >> 11) + 1);
+ dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
+ }
+ }
+ if (!(dev->isoc_in_endpointaddr)) {
+ printk(KERN_INFO "Could not locate isoc endpoint\n");
+ kfree(dev);
+ return -ENODEV;
+ }
+
+ init_waitqueue_head(&dev->open);
+ spin_lock_init(&dev->slock);
+ mutex_init(&dev->lock);
+
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+
+ dev->width = NTSC_STD_W;
+ dev->height = NTSC_STD_H;
+ dev->field_size = dev->width * dev->height;
+ dev->frame_size = dev->field_size << 1;
+ dev->bytesperline = dev->width << 1;
+ dev->ctrl_ainput = 0;
+
+ /* allocate and fill v4l2 video struct */
+ dev->vdev = video_device_alloc();
+ if (NULL == dev->vdev) {
+ dprintk(1, "Can't allocate video_device.\n");
+ return -ENOMEM;
+ }
+
+#ifdef VBI_IS_WORKING
+ dev->vbi_dev = video_device_alloc();
+ if (NULL == dev->vbi_dev) {
+ dprintk(1, "Can't allocate vbi_device.\n");
+ kfree(dev->vdev);
+ return -ENOMEM;
+ }
+#endif
+
+ /* Fill the video capture device struct */
+ *dev->vdev = au0828_video_template;
+ dev->vdev->parent = &dev->usbdev->dev;
+ strcpy(dev->vdev->name, "au0828a video");
+
+#ifdef VBI_IS_WORKING
+ /* Setup the VBI device */
+ *dev->vbi_dev = au0828_video_template;
+ dev->vbi_dev->parent = &dev->usbdev->dev;
+ strcpy(dev->vbi_dev->name, "au0828a vbi");
+#endif
+
+ list_add_tail(&dev->au0828list, &au0828_devlist);
+
+ /* Register the v4l2 device */
+ retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (retval != 0) {
+ dprintk(1, "unable to register video device (error = %d).\n",
+ retval);
+ list_del(&dev->au0828list);
+ video_device_release(dev->vdev);
+ return -ENODEV;
+ }
+
+#ifdef VBI_IS_WORKING
+ /* Register the vbi device */
+ retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
+ if (retval != 0) {
+ dprintk(1, "unable to register vbi device (error = %d).\n",
+ retval);
+ list_del(&dev->au0828list);
+ video_device_release(dev->vbi_dev);
+ video_device_release(dev->vdev);
+ return -ENODEV;
+ }
+#endif
+
+ dprintk(1, "%s completed!\n", __func__);
+
+ return 0;
+}
+
diff --git a/linux/drivers/media/video/au0828/au0828.h b/linux/drivers/media/video/au0828/au0828.h
index 9d6a1161d..6ed1a6129 100644
--- a/linux/drivers/media/video/au0828/au0828.h
+++ b/linux/drivers/media/video/au0828/au0828.h
@@ -24,6 +24,11 @@
#include <linux/i2c-algo-bit.h>
#include <media/tveeprom.h>
+/* Analog */
+#include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+
/* DVB */
#include "demux.h"
#include "dmxdev.h"
@@ -39,8 +44,45 @@
#define URB_COUNT 16
#define URB_BUFSIZE (0xe522)
+/* Analog constants */
+#define NTSC_STD_W 720
+#define NTSC_STD_H 480
+
+#define AU0828_INTERLACED_DEFAULT 1
+#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
+
+/* Defination for AU0828 USB transfer */
+#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
+#define AU0828_ISO_PACKETS_PER_URB 10
+
+#define AU0828_MIN_BUF 4
+#define AU0828_DEF_BUF 8
+
+#define AU0828_MAX_INPUT 4
+
+enum au0828_itype {
+ AU0828_VMUX_UNDEFINED = 0,
+ AU0828_VMUX_COMPOSITE,
+ AU0828_VMUX_SVIDEO,
+ AU0828_VMUX_CABLE,
+ AU0828_VMUX_TELEVISION,
+ AU0828_VMUX_DVB,
+ AU0828_VMUX_DEBUG
+};
+
+struct au0828_input {
+ enum au0828_itype type;
+ unsigned int vmux;
+ unsigned int amux;
+ void (*audio_setup) (void *priv, int enable);
+};
+
struct au0828_board {
char *name;
+ unsigned int tuner_type;
+ unsigned char tuner_addr;
+ struct au0828_input input[AU0828_MAX_INPUT];
+
};
struct au0828_dvb {
@@ -55,31 +97,143 @@ struct au0828_dvb {
int feeding;
};
+enum au0828_stream_state {
+ STREAM_OFF,
+ STREAM_INTERRUPT,
+ STREAM_ON
+};
+
+#define AUVI_INPUT(nr) (dev->board.input[nr])
+
+/* device state */
+enum au0828_dev_state {
+ DEV_INITIALIZED = 0x01,
+ DEV_DISCONNECTED = 0x02,
+ DEV_MISCONFIGURED = 0x04
+};
+
+struct au0828_fh {
+ struct au0828_dev *dev;
+ unsigned int stream_on:1; /* Locks streams */
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+};
+
+struct au0828_usb_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct au0828_buffer *buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+
+ /* isoc urb callback */
+ int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
+
+};
+
+/* buffer for one video frame */
+struct au0828_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ struct list_head frame;
+ int top_field;
+ int receiving;
+};
+
+struct au0828_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+
+ wait_queue_head_t wq;
+
+ /* Counters to control buffer fill */
+ int pos;
+};
+
struct au0828_dev {
struct mutex mutex;
struct usb_device *usbdev;
- int board;
+ int boardnr;
+ struct au0828_board board;
u8 ctrlmsg[64];
/* I2C */
struct i2c_adapter i2c_adap;
- struct i2c_algo_bit_data i2c_algo;
+ struct i2c_algorithm i2c_algo;
struct i2c_client i2c_client;
u32 i2c_rc;
/* Digital */
struct au0828_dvb dvb;
+ /* Analog */
+ struct list_head au0828list;
+ struct v4l2_device v4l2_dev;
+ int users;
+ unsigned int stream_on:1; /* Locks streams */
+ struct video_device *vdev;
+ struct video_device *vbi_dev;
+ int width;
+ int height;
+ u32 field_size;
+ u32 frame_size;
+ u32 bytesperline;
+ int type;
+ u8 ctrl_ainput;
+ __u8 isoc_in_endpointaddr;
+ u8 isoc_init_ok;
+ int greenscreen_detected;
+ unsigned int frame_count;
+ int ctrl_freq;
+ int input_type;
+ unsigned int ctrl_input;
+ enum au0828_dev_state dev_state;
+ enum au0828_stream_state stream_state;
+ wait_queue_head_t open;
+
+ struct mutex lock;
+
+ /* Isoc control struct */
+ struct au0828_dmaqueue vidq;
+ struct au0828_usb_isoc_ctl isoc_ctl;
+ spinlock_t slock;
+
+ /* usb transfer */
+ int alt; /* alternate */
+ int max_pkt_size; /* max packet size of isoc transaction */
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ struct urb *urb[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */
+ char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
+ transfer */
+
/* USB / URB Related */
int urb_streaming;
struct urb *urbs[URB_COUNT];
-
-};
-
-struct au0828_buff {
- struct au0828_dev *dev;
- struct urb *purb;
- struct list_head buff_list;
};
/* ----------------------------------------------------------- */
@@ -111,8 +265,13 @@ extern void au0828_card_setup(struct au0828_dev *dev);
/* au0828-i2c.c */
extern int au0828_i2c_register(struct au0828_dev *dev);
extern int au0828_i2c_unregister(struct au0828_dev *dev);
-extern void au0828_call_i2c_clients(struct au0828_dev *dev,
- unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------- */
+/* au0828-video.c */
+int au0828_analog_register(struct au0828_dev *dev,
+ struct usb_interface *interface);
+int au0828_analog_stream_disable(struct au0828_dev *d);
+void au0828_analog_unregister(struct au0828_dev *dev);
/* ----------------------------------------------------------- */
/* au0828-dvb.c */
diff --git a/linux/drivers/media/video/bt819.c b/linux/drivers/media/video/bt819.c
index ec64197e9..b8c084acf 100644
--- a/linux/drivers/media/video/bt819.c
+++ b/linux/drivers/media/video/bt819.c
@@ -32,13 +32,13 @@
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
-#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
+#include <media/bt819.h>
#include "compat.h"
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
@@ -254,9 +254,13 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
struct bt819 *decoder = to_bt819(sd);
struct timing *timing = NULL;
- v4l2_dbg(1, debug, sd, "set norm %llx\n", std);
+ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+ if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
+ v4l2_err(sd, "no notify found!\n");
if (std & V4L2_STD_NTSC) {
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
bt819_setbit(decoder, 0x01, 0, 1);
bt819_setbit(decoder, 0x01, 1, 0);
bt819_setbit(decoder, 0x01, 5, 0);
@@ -265,6 +269,7 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* bt819_setbit(decoder, 0x1a, 5, 1); */
timing = &timing_data[1];
} else if (std & V4L2_STD_PAL) {
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
bt819_setbit(decoder, 0x01, 0, 1);
bt819_setbit(decoder, 0x01, 1, 1);
bt819_setbit(decoder, 0x01, 5, 1);
@@ -273,7 +278,8 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* bt819_setbit(decoder, 0x1a, 5, 0); */
timing = &timing_data[0];
} else {
- v4l2_dbg(1, debug, sd, "unsupported norm %llx\n", std);
+ v4l2_dbg(1, debug, sd, "unsupported norm %llx\n",
+ (unsigned long long)std);
return -EINVAL;
}
bt819_write(decoder, 0x03,
@@ -288,6 +294,7 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff);
bt819_write(decoder, 0x09, timing->hscale & 0xff);
decoder->norm = std;
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
return 0;
}
@@ -300,7 +307,11 @@ static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *ro
if (route->input < 0 || route->input > 7)
return -EINVAL;
+ if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
+ v4l2_err(sd, "no notify found!\n");
+
if (decoder->input != route->input) {
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
decoder->input = route->input;
/* select mode */
if (decoder->input == 0) {
@@ -310,6 +321,7 @@ static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *ro
bt819_setbit(decoder, 0x0b, 6, 1);
bt819_setbit(decoder, 0x1a, 1, 0);
}
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
}
return 0;
}
diff --git a/linux/drivers/media/video/bt856.c b/linux/drivers/media/video/bt856.c
index fc7b64d91..ab56d7d6e 100644
--- a/linux/drivers/media/video/bt856.c
+++ b/linux/drivers/media/video/bt856.c
@@ -131,7 +131,7 @@ static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct bt856 *encoder = to_bt856(sd);
- v4l2_dbg(1, debug, sd, "set norm %llx\n", std);
+ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
if (std & V4L2_STD_NTSC) {
bt856_setbit(encoder, 0xdc, 2, 0);
diff --git a/linux/drivers/media/video/bt866.c b/linux/drivers/media/video/bt866.c
index edc1aa348..5ea31375e 100644
--- a/linux/drivers/media/video/bt866.c
+++ b/linux/drivers/media/video/bt866.c
@@ -97,7 +97,7 @@ static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
{
- v4l2_dbg(1, debug, sd, "set norm %llx\n", std);
+ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
/* Only PAL supported by this driver at the moment! */
if (!(std & V4L2_STD_NTSC))
diff --git a/linux/drivers/media/video/bt8xx/Kconfig b/linux/drivers/media/video/bt8xx/Kconfig
index ce71e8e7b..94c9df8b1 100644
--- a/linux/drivers/media/video/bt8xx/Kconfig
+++ b/linux/drivers/media/video/bt8xx/Kconfig
@@ -10,7 +10,6 @@ config VIDEO_BT848
select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_TDA9875 if VIDEO_HELPER_CHIPS_AUTO
---help---
Support for BT848 based frame grabber/overlay boards. This includes
the Miro, Hauppauge and STB boards. Please read the material in
diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c
index a2719c6bd..1c13dbfec 100644
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c
@@ -76,6 +76,9 @@ static void geovision_muxsel(struct bttv *btv, unsigned int input);
static void phytec_muxsel(struct bttv *btv, unsigned int input);
+static void gv800s_muxsel(struct bttv *btv, unsigned int input);
+static void gv800s_init(struct bttv *btv);
+
static int terratec_active_radio_upgrade(struct bttv *btv);
static int tea5757_read(struct bttv *btv);
static int tea5757_write(struct bttv *btv, int value);
@@ -94,12 +97,10 @@ static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int audiodev[BTTV_MAX];
+static unsigned int saa6588[BTTV_MAX];
static struct bttv *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
-#ifdef MODULE
-static unsigned int autoload = 1;
-#else
-static unsigned int autoload;
-#endif
+static unsigned int autoload = UNSET;
static unsigned int gpiomask = UNSET;
static unsigned int audioall = UNSET;
static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
@@ -118,6 +119,7 @@ module_param_array(pll, int, NULL, 0444);
module_param_array(tuner, int, NULL, 0444);
module_param_array(svhs, int, NULL, 0444);
module_param_array(remote, int, NULL, 0444);
+module_param_array(audiodev, int, NULL, 0444);
module_param_array(audiomux, int, NULL, 0444);
MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
@@ -128,7 +130,14 @@ MODULE_PARM_DESC(latency,"pci latency timer");
MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
MODULE_PARM_DESC(tuner,"specify installed tuner type");
-MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
+MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore");
+MODULE_PARM_DESC(audiodev, "specify audio device:\n"
+ "\t\t-1 = no audio\n"
+ "\t\t 0 = autodetect (default)\n"
+ "\t\t 1 = msp3400\n"
+ "\t\t 2 = tda7432\n"
+ "\t\t 3 = tvaudio");
+MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition.");
MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
" [some VIA/SIS chipsets are known to have problem with overlay]");
@@ -296,6 +305,8 @@ static struct CARD {
/* Duplicate PCI ID, reconfigure for this board during the eeprom read.
* { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */
+ { 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2, "Conceptronic CTVFMi v2"},
+
/* DVB cards (using pci function .1 for mpeg data xfer) */
{ 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" },
{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
@@ -312,6 +323,20 @@ static struct CARD {
{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" },
{ 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" },
{ 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" },
+ { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" },
+ { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
+ { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
+ { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
+
+ { 0x15401830, BTTV_BOARD_PV183, "Provideo PV183-1" },
+ { 0x15401831, BTTV_BOARD_PV183, "Provideo PV183-2" },
+ { 0x15401832, BTTV_BOARD_PV183, "Provideo PV183-3" },
+ { 0x15401833, BTTV_BOARD_PV183, "Provideo PV183-4" },
+ { 0x15401834, BTTV_BOARD_PV183, "Provideo PV183-5" },
+ { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" },
+ { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" },
+ { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" },
+
{ 0, -1, NULL }
};
@@ -2847,7 +2872,74 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
- }
+ },
+ [BTTV_BOARD_GEOVISION_GV800S] = {
+ /* Bruno Christo <bchristo@inf.ufsm.br>
+ *
+ * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+ * 1 audio input per BT878A = 4 audio inputs
+ * 4 video inputs per BT878A = 16 video inputs
+ * This is the first BT878A chip of the GV-800(S). It's the
+ * "master" chip and it controls the video inputs through an
+ * analog multiplexer (a CD22M3494) via some GPIO pins. The
+ * slaves should use card type 0x9e (following this one).
+ * There is a EEPROM on the card which is currently not handled.
+ * The audio input is not working yet.
+ */
+ .name = "Geovision GV-800(S) (master)",
+ .video_inputs = 4,
+ /* .audio_inputs= 1, */
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .svhs = NO_SVHS,
+ .gpiomask = 0xf107f,
+ .no_gpioirq = 1,
+ .muxsel = MUXSEL(2, 2, 2, 2),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = gv800s_muxsel,
+ },
+ [BTTV_BOARD_GEOVISION_GV800S_SL] = {
+ /* Bruno Christo <bchristo@inf.ufsm.br>
+ *
+ * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+ * 1 audio input per BT878A = 4 audio inputs
+ * 4 video inputs per BT878A = 16 video inputs
+ * The 3 other BT878A chips are "slave" chips of the GV-800(S)
+ * and should use this card type.
+ * The audio input is not working yet.
+ */
+ .name = "Geovision GV-800(S) (slave)",
+ .video_inputs = 4,
+ /* .audio_inputs= 1, */
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .svhs = NO_SVHS,
+ .gpiomask = 0x00,
+ .no_gpioirq = 1,
+ .muxsel = MUXSEL(2, 2, 2, 2),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = gv800s_muxsel,
+ },
+ [BTTV_BOARD_PV183] = {
+ .name = "ProVideo PV183", /* 0x9f */
+ .video_inputs = 2,
+ /* .audio_inputs= 0, */
+ .svhs = NO_SVHS,
+ .gpiomask = 0,
+ .muxsel = MUXSEL(2, 3),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2891,7 +2983,7 @@ void __devinit bttv_idcard(struct bttv *btv)
btv->c.nr, btv->cardid & 0xffff,
(btv->cardid >> 16) & 0xffff);
printk(KERN_DEBUG "please mail id, board name and "
- "the correct card= insmod option to video4linux-list@redhat.com\n");
+ "the correct card= insmod option to linux-media@vger.kernel.org\n");
}
}
@@ -3270,6 +3362,17 @@ void __devinit bttv_init_card1(struct bttv *btv)
/* initialization part two -- after registering i2c bus */
void __devinit bttv_init_card2(struct bttv *btv)
{
+ static const unsigned short tvaudio_addrs[] = {
+ I2C_ADDR_TDA8425 >> 1,
+ I2C_ADDR_TEA6300 >> 1,
+ I2C_ADDR_TEA6420 >> 1,
+ I2C_ADDR_TDA9840 >> 1,
+ I2C_ADDR_TDA985x_L >> 1,
+ I2C_ADDR_TDA985x_H >> 1,
+ I2C_ADDR_TDA9874 >> 1,
+ I2C_ADDR_PIC16C54 >> 1,
+ I2C_CLIENT_END
+ };
int addr=ADDR_UNSET;
btv->tuner_type = UNSET;
@@ -3376,6 +3479,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
case BTTV_BOARD_KODICOM_4400R:
kodicom4400r_init(btv);
break;
+ case BTTV_BOARD_GEOVISION_GV800S:
+ gv800s_init(btv);
+ break;
}
/* pll configuration */
@@ -3430,6 +3536,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
btv->tuner_type);
+ if (autoload != UNSET) {
+ printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr);
+ printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr);
+ printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr);
+ }
+
if (UNSET == btv->tuner_type)
btv->tuner_type = TUNER_ABSENT;
@@ -3437,8 +3549,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
struct tuner_setup tun_setup;
/* Load tuner module before issuing tuner config call! */
- if (autoload)
- request_module("tuner");
+ if (bttv_tvcards[btv->c.type].has_radio)
+ v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+ v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
+ "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
+ "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
tun_setup.type = btv->tuner_type;
@@ -3447,7 +3564,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (bttv_tvcards[btv->c.type].has_radio)
tun_setup.mode_mask |= T_RADIO;
- bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+ bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
}
if (btv->tda9887_conf) {
@@ -3456,7 +3573,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
tda9887_cfg.tuner = TUNER_TDA9887;
tda9887_cfg.priv = &btv->tda9887_conf;
- bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
+ bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
}
btv->dig = bttv_tvcards[btv->c.type].has_dig_in ?
@@ -3479,31 +3596,127 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (bttv_tvcards[btv->c.type].audio_mode_gpio)
btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
- if (!autoload)
- return;
-
if (btv->tuner_type == TUNER_ABSENT)
return; /* no tuner or related drivers to load */
+ if (btv->has_saa6588 || saa6588[btv->c.nr]) {
+ /* Probe for RDS receiver chip */
+ static const unsigned short addrs[] = {
+ 0x20 >> 1,
+ 0x22 >> 1,
+ I2C_CLIENT_END
+ };
+ struct v4l2_subdev *sd;
+
+ sd = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "saa6588", "saa6588", addrs);
+ btv->has_saa6588 = (sd != NULL);
+ }
+
/* try to detect audio/fader chips */
- if (!bttv_tvcards[btv->c.type].no_msp34xx &&
- bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
- request_module("msp3400");
- if (bttv_tvcards[btv->c.type].msp34xx_alt &&
- bttv_I2CRead(btv, I2C_ADDR_MSP3400_ALT, "MSP34xx (alternate address)") >=0)
- request_module("msp3400");
+ /* First check if the user specified the audio chip via a module
+ option. */
+
+ switch (audiodev[btv->c.nr]) {
+ case -1:
+ return; /* do not load any audio module */
+
+ case 0: /* autodetect */
+ break;
+
+ case 1: {
+ /* The user specified that we should probe for msp3400 */
+ static const unsigned short addrs[] = {
+ I2C_ADDR_MSP3400 >> 1,
+ I2C_ADDR_MSP3400_ALT >> 1,
+ I2C_CLIENT_END
+ };
+
+ btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "msp3400", "msp3400", addrs);
+ if (btv->sd_msp34xx)
+ return;
+ goto no_audio;
+ }
+
+ case 2: {
+ /* The user specified that we should probe for tda7432 */
+ static const unsigned short addrs[] = {
+ I2C_ADDR_TDA7432 >> 1,
+ I2C_CLIENT_END
+ };
- if (!bttv_tvcards[btv->c.type].no_tda9875 &&
- bttv_I2CRead(btv, I2C_ADDR_TDA9875, "TDA9875") >=0)
- request_module("tda9875");
+ if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "tda7432", "tda7432", addrs))
+ return;
+ goto no_audio;
+ }
- if (!bttv_tvcards[btv->c.type].no_tda7432 &&
- bttv_I2CRead(btv, I2C_ADDR_TDA7432, "TDA7432") >=0)
- request_module("tda7432");
+ case 3: {
+ /* The user specified that we should probe for tvaudio */
+ btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "tvaudio", "tvaudio", tvaudio_addrs);
+ if (btv->sd_tvaudio)
+ return;
+ goto no_audio;
+ }
- if (bttv_tvcards[btv->c.type].needs_tvaudio)
- request_module("tvaudio");
+ default:
+ printk(KERN_WARNING "bttv%d: unknown audiodev value!\n",
+ btv->c.nr);
+ return;
+ }
+
+ /* There were no overrides, so now we try to discover this through the
+ card definition */
+
+ /* probe for msp3400 first: this driver can detect whether or not
+ it really is a msp3400, so it will return NULL when the device
+ found is really something else (e.g. a tea6300). */
+ if (!bttv_tvcards[btv->c.type].no_msp34xx) {
+ static const unsigned short addrs[] = {
+ I2C_ADDR_MSP3400 >> 1,
+ I2C_CLIENT_END
+ };
+
+ btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "msp3400", "msp3400", addrs);
+ } else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
+ static const unsigned short addrs[] = {
+ I2C_ADDR_MSP3400_ALT >> 1,
+ I2C_CLIENT_END
+ };
+
+ btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "msp3400", "msp3400", addrs);
+ }
+
+ /* If we found a msp34xx, then we're done. */
+ if (btv->sd_msp34xx)
+ return;
+
+ /* it might also be a tda7432. */
+ if (!bttv_tvcards[btv->c.type].no_tda7432) {
+ static const unsigned short addrs[] = {
+ I2C_ADDR_TDA7432 >> 1,
+ I2C_CLIENT_END
+ };
+
+ if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "tda7432", "tda7432", addrs))
+ return;
+ }
+
+ /* Now see if we can find one of the tvaudio devices. */
+ btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
+ "tvaudio", "tvaudio", tvaudio_addrs);
+ if (btv->sd_tvaudio)
+ return;
+
+no_audio:
+ printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n",
+ btv->c.nr);
}
@@ -3575,6 +3788,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
printk("bttv%d: Terratec Active Radio Upgrade found.\n",
btv->c.nr);
btv->has_radio = 1;
+ btv->has_saa6588 = 1;
btv->has_matchbox = 1;
} else {
btv->has_radio = 0;
@@ -3681,7 +3895,11 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
unsigned short type;
for (i = 4*16; i < 8*16; i += 16) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ u16 checksum = ip_compute_csum((unsigned char *)(ee + i), 16);
+#else
u16 checksum = ip_compute_csum(ee + i, 16);
+#endif
if ((checksum&0xff) + (checksum>>8) == 0xff)
break;
@@ -4595,6 +4813,122 @@ static void phytec_muxsel(struct bttv *btv, unsigned int input)
gpio_bits(0x3, mux);
}
+/*
+ * GeoVision GV-800(S) functions
+ * Bruno Christo <bchristo@inf.ufsm.br>
+*/
+
+/* This is a function to control the analog switch, which determines which
+ * camera is routed to which controller. The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 18) of '1' enables the switch, and '0' disables
+ * the switch. A STROBE bit (gpio bit 17) latches the data value into the
+ * specified address. There is also a chip select (gpio bit 16).
+ * The idea is to set the address and chip select together, bring
+ * STROBE high, write the data, and finally bring STROBE back to low.
+ */
+static void gv800s_write(struct bttv *btv,
+ unsigned char xaddr,
+ unsigned char yaddr,
+ unsigned char data) {
+ /* On the "master" 878A:
+ * GPIO bits 0-9 are used for the analog switch:
+ * 00 - 03: camera selector
+ * 04 - 06: 878A (controller) selector
+ * 16: cselect
+ * 17: strobe
+ * 18: data (1->on, 0->off)
+ * 19: reset
+ */
+ const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4);
+ const u32 CSELECT = 1<<16;
+ const u32 STROBE = 1<<17;
+ const u32 DATA = data<<18;
+
+ gpio_bits(0x1007f, ADDRESS | CSELECT); /* write ADDRESS and CSELECT */
+ gpio_bits(0x20000, STROBE); /* STROBE high */
+ gpio_bits(0x40000, DATA); /* write DATA */
+ gpio_bits(0x20000, ~STROBE); /* STROBE low */
+}
+
+/*
+ * GeoVision GV-800(S) muxsel
+ *
+ * Each of the 4 cards (controllers) use this function.
+ * The controller using this function selects the input through the GPIO pins
+ * of the "master" card. A pointer to this card is stored in master[btv->c.nr].
+ *
+ * The parameter 'input' is the requested camera number (0-4) on the controller.
+ * The map array has the address of each input. Note that the addresses in the
+ * array are in the sequence the original GeoVision driver uses, that is, set
+ * every controller to input 0, then to input 1, 2, 3, repeat. This means that
+ * the physical "camera 1" connector corresponds to controller 0 input 0,
+ * "camera 2" corresponds to controller 1 input 0, and so on.
+ *
+ * After getting the input address, the function then writes the appropriate
+ * data to the analog switch, and housekeeps the local copy of the switch
+ * information.
+ */
+static void gv800s_muxsel(struct bttv *btv, unsigned int input)
+{
+ struct bttv *mctlr;
+ char *sw_status;
+ int xaddr, yaddr;
+ static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
+ { 0x1, 0x5, 0xb, 0x7 },
+ { 0x2, 0x8, 0xc, 0xe },
+ { 0x3, 0x9, 0xd, 0xf } };
+ input = input%4;
+ mctlr = master[btv->c.nr];
+ if (mctlr == NULL) {
+ /* do nothing until the "master" is detected */
+ return;
+ }
+ yaddr = (btv->c.nr - mctlr->c.nr) & 3;
+ sw_status = (char *)(&mctlr->mbox_we);
+ xaddr = map[yaddr][input] & 0xf;
+
+ /* Check if the controller/camera pair has changed, ignore otherwise */
+ if (sw_status[yaddr] != xaddr) {
+ /* disable the old switch, enable the new one and save status */
+ gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
+ sw_status[yaddr] = xaddr;
+ gv800s_write(mctlr, xaddr, yaddr, 1);
+ }
+}
+
+/* GeoVision GV-800(S) "master" chip init */
+static void gv800s_init(struct bttv *btv)
+{
+ char *sw_status = (char *)(&btv->mbox_we);
+ int ix;
+
+ gpio_inout(0xf107f, 0xf107f);
+ gpio_write(1<<19); /* reset the analog MUX */
+ gpio_write(0);
+
+ /* Preset camera 0 to the 4 controllers */
+ for (ix = 0; ix < 4; ix++) {
+ sw_status[ix] = ix;
+ gv800s_write(btv, ix, ix, 1);
+ }
+
+ /* Inputs on the "master" controller need this brightness fix */
+ bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
+
+ if (btv->c.nr > BTTV_MAX-4)
+ return;
+ /*
+ * Store the "master" controller pointer in the master
+ * array for later use in the muxsel function.
+ */
+ master[btv->c.nr] = btv;
+ master[btv->c.nr+1] = btv;
+ master[btv->c.nr+2] = btv;
+ master[btv->c.nr+3] = btv;
+}
+
/* ----------------------------------------------------------------------- */
/* motherboard chipset specific stuff */
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index ab202761b..f40eb10fd 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -171,7 +171,7 @@ static ssize_t show_card(struct class_device *cd, char *buf)
#endif
{
struct video_device *vfd = container_of(cd, struct video_device, dev);
- struct bttv *btv = dev_get_drvdata(vfd->parent);
+ struct bttv *btv = video_get_drvdata(vfd);
return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
@@ -1181,7 +1181,6 @@ audio_mux(struct bttv *btv, int input, int mute)
{
int gpio_val, signal;
struct v4l2_control ctrl;
- struct i2c_client *c;
gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
bttv_tvcards[btv->c.type].gpiomask);
@@ -1220,9 +1219,8 @@ audio_mux(struct bttv *btv, int input, int mute)
ctrl.id = V4L2_CID_AUDIO_MUTE;
ctrl.value = btv->mute;
- bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
- c = btv->i2c_msp34xx_client;
- if (c) {
+ bttv_call_all(btv, core, s_ctrl, &ctrl);
+ if (btv->sd_msp34xx) {
struct v4l2_routing route;
/* Note: the inputs tuner/radio/extern/intern are translated
@@ -1261,15 +1259,14 @@ audio_mux(struct bttv *btv, int input, int mute)
break;
}
route.output = MSP_OUTPUT_DEFAULT;
- c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, &route);
}
- c = btv->i2c_tvaudio_client;
- if (c) {
+ if (btv->sd_tvaudio) {
struct v4l2_routing route;
route.input = input;
route.output = 0;
- c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, &route);
}
return 0;
}
@@ -1360,7 +1357,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
#endif
}
id = tvnorm->v4l2_id;
- bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
+ bttv_call_all(btv, tuner, s_std, id);
return 0;
}
@@ -1504,7 +1501,7 @@ static int bttv_g_ctrl(struct file *file, void *priv,
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
- bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
+ bttv_call_all(btv, core, g_ctrl, c);
break;
case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1578,12 +1575,12 @@ static int bttv_s_ctrl(struct file *file, void *f,
if (btv->volume_gpio)
btv->volume_gpio(btv, c->value);
- bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+ bttv_call_all(btv, core, s_ctrl, c);
break;
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
- bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+ bttv_call_all(btv, core, s_ctrl, c);
break;
case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1922,16 +1919,11 @@ static int bttv_enum_input(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- unsigned int n;
+ int n;
- n = i->index;
-
- if (n >= bttv_tvcards[btv->c.type].video_inputs)
+ if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
return -EINVAL;
- memset(i, 0, sizeof(*i));
-
- i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->audioset = 1;
@@ -2006,7 +1998,7 @@ static int bttv_s_tuner(struct file *file, void *priv,
return -EINVAL;
mutex_lock(&btv->lock);
- bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
+ bttv_call_all(btv, tuner, s_tuner, t);
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 1);
@@ -2051,7 +2043,7 @@ static int bttv_s_frequency(struct file *file, void *priv,
return -EINVAL;
mutex_lock(&btv->lock);
btv->freq = f->frequency;
- bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
+ bttv_call_all(btv, tuner, s_frequency, f);
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv, btv->freq);
mutex_unlock(&btv->lock);
@@ -2065,7 +2057,7 @@ static int bttv_log_status(struct file *file, void *f)
printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n",
btv->c.nr, btv->c.nr);
- bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+ bttv_call_all(btv, core, log_status);
printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n",
btv->c.nr, btv->c.nr);
return 0;
@@ -2960,13 +2952,9 @@ static int bttv_g_parm(struct file *file, void *f,
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- struct v4l2_standard s;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
- bttv_tvnorms[btv->tvnorm].name);
- parm->parm.capture.timeperframe = s.frameperiod;
+ v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
+ &parm->parm.capture.timeperframe);
return 0;
}
@@ -2982,9 +2970,8 @@ static int bttv_g_tuner(struct file *file, void *priv,
return -EINVAL;
mutex_lock(&btv->lock);
- memset(t, 0, sizeof(*t));
t->rxsubchans = V4L2_TUNER_SUB_MONO;
- bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+ bttv_call_all(btv, tuner, g_tuner, t);
strcpy(t->name, "Television");
t->capability = V4L2_TUNER_CAP_NORM;
t->type = V4L2_TUNER_ANALOG_TV;
@@ -3475,7 +3462,7 @@ static int radio_open(struct file *file)
btv->radio_user++;
- bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
+ bttv_call_all(btv, tuner, s_radio);
audio_input(btv,TVAUDIO_INPUT_RADIO);
mutex_unlock(&btv->lock);
@@ -3495,7 +3482,7 @@ static int radio_release(struct file *file)
btv->radio_user--;
- bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
+ bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
return 0;
}
@@ -3525,11 +3512,10 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (0 != t->index)
return -EINVAL;
mutex_lock(&btv->lock);
- memset(t, 0, sizeof(*t));
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
- bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+ bttv_call_all(btv, tuner, g_tuner, t);
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
@@ -3571,7 +3557,7 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+ bttv_call_all(btv, tuner, g_tuner, t);
return 0;
}
@@ -3632,7 +3618,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
cmd.instance = file;
cmd.result = -ENODEV;
- bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
+ bttv_call_all(btv, core, ioctl, RDS_CMD_READ, &cmd);
return cmd.result;
}
@@ -3645,7 +3631,7 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
cmd.instance = file;
cmd.event_list = wait;
cmd.result = -ENODEV;
- bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
+ bttv_call_all(btv, core, ioctl, RDS_CMD_POLL, &cmd);
return cmd.result;
}
@@ -3729,14 +3715,14 @@ static void bttv_risc_disasm(struct bttv *btv,
unsigned int i,j,n;
printk("%s: risc disasm: %p [dma=0x%08lx]\n",
- btv->c.name, risc->cpu, (unsigned long)risc->dma);
+ btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma);
for (i = 0; i < (risc->size >> 2); i += n) {
- printk("%s: 0x%lx: ", btv->c.name,
+ printk("%s: 0x%lx: ", btv->c.v4l2_dev.name,
(unsigned long)(risc->dma + (i<<2)));
n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
for (j = 1; j < n; j++)
printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
- btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
+ btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)),
risc->cpu[i+j], j);
if (0 == risc->cpu[i])
break;
@@ -4216,7 +4202,7 @@ static struct video_device *vdev_init(struct bttv *btv,
return NULL;
*vfd = *template;
vfd->minor = -1;
- vfd->parent = &btv->c.pci->dev;
+ vfd->v4l2_dev = &btv->c.v4l2_dev;
vfd->release = video_device_release;
vfd->debug = bttv_debug;
video_set_drvdata(vfd, btv);
@@ -4335,8 +4321,13 @@ static int __devinit bttv_probe(struct pci_dev *dev,
return -ENOMEM;
printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL);
+ if (btv == NULL) {
+ printk(KERN_ERR "bttv: out of memory.\n");
+ return -ENOMEM;
+ }
btv->c.nr = bttv_num;
- sprintf(btv->c.name,"bttv%d",btv->c.nr);
+ snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name),
+ "bttv%d", btv->c.nr);
/* initialize structs / fill in defaults */
mutex_init(&btv->lock);
@@ -4373,7 +4364,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
}
if (!request_mem_region(pci_resource_start(dev,0),
pci_resource_len(dev,0),
- btv->c.name)) {
+ btv->c.v4l2_dev.name)) {
printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
btv->c.nr,
(unsigned long long)pci_resource_start(dev,0));
@@ -4381,7 +4372,12 @@ static int __devinit bttv_probe(struct pci_dev *dev,
}
pci_set_master(dev);
pci_set_command(dev);
- pci_set_drvdata(dev,btv);
+
+ result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev);
+ if (result < 0) {
+ printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr);
+ goto fail0;
+ }
pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
@@ -4405,7 +4401,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* disable irqs, register irq handler */
btwrite(0, BT848_INT_MASK);
result = request_irq(btv->c.pci->irq, bttv_irq,
- IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
+ IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv);
if (result < 0) {
printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
bttv_num,btv->c.pci->irq);
@@ -4489,21 +4485,24 @@ static int __devinit bttv_probe(struct pci_dev *dev,
bttv_num++;
return 0;
- fail2:
+fail2:
free_irq(btv->c.pci->irq,btv);
- fail1:
+fail1:
+ v4l2_device_unregister(&btv->c.v4l2_dev);
+
+fail0:
if (btv->bt848_mmio)
iounmap(btv->bt848_mmio);
release_mem_region(pci_resource_start(btv->c.pci,0),
pci_resource_len(btv->c.pci,0));
- pci_set_drvdata(dev,NULL);
return result;
}
static void __devexit bttv_remove(struct pci_dev *pci_dev)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct bttv *btv = to_bttv(v4l2_dev);
if (bttv_verbose)
printk("bttv%d: unloading\n",btv->c.nr);
@@ -4537,7 +4536,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
release_mem_region(pci_resource_start(btv->c.pci,0),
pci_resource_len(btv->c.pci,0));
- pci_set_drvdata(pci_dev, NULL);
+ v4l2_device_unregister(&btv->c.v4l2_dev);
bttvs[btv->c.nr] = NULL;
kfree(btv);
@@ -4547,7 +4546,8 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
#ifdef CONFIG_PM
static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct bttv *btv = to_bttv(v4l2_dev);
struct bttv_buffer_set idle;
unsigned long flags;
@@ -4582,7 +4582,8 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
static int bttv_resume(struct pci_dev *pci_dev)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct bttv *btv = to_bttv(v4l2_dev);
unsigned long flags;
int err;
diff --git a/linux/drivers/media/video/bt8xx/bttv-i2c.c b/linux/drivers/media/video/bt8xx/bttv-i2c.c
index 66fc4e480..dbb21f77b 100644
--- a/linux/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/linux/drivers/media/video/bt8xx/bttv-i2c.c
@@ -36,8 +36,6 @@
#include <linux/jiffies.h>
#include <asm/io.h>
-static int attach_inform(struct i2c_client *client);
-
static int i2c_debug;
static int i2c_hw;
static int i2c_scan;
@@ -231,7 +229,8 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
{
- struct bttv *btv = i2c_get_adapdata(i2c_adap);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
+ struct bttv *btv = to_bttv(v4l2_dev);
int retval = 0;
int i;
@@ -268,50 +267,6 @@ static const struct i2c_algorithm bttv_algo = {
/* ----------------------------------------------------------------------- */
/* I2C functions - common stuff */
-static int attach_inform(struct i2c_client *client)
-{
- struct bttv *btv = i2c_get_adapdata(client->adapter);
- int addr=ADDR_UNSET;
-
-
- if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
- addr = bttv_tvcards[btv->c.type].tuner_addr;
-
-
- if (bttv_debug)
- printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
- btv->c.nr, client->driver->driver.name, client->addr,
- client->name);
- if (!client->driver->command)
- return 0;
-
- if (client->driver->id == I2C_DRIVERID_MSP3400)
- btv->i2c_msp34xx_client = client;
- if (client->driver->id == I2C_DRIVERID_TVAUDIO)
- btv->i2c_tvaudio_client = client;
- if (btv->tuner_type != TUNER_ABSENT) {
- struct tuner_setup tun_setup;
-
- if (addr == ADDR_UNSET || addr == client->addr) {
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
- tun_setup.type = btv->tuner_type;
- tun_setup.addr = addr;
- bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
-
- }
-
- return 0;
-}
-
-void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
-{
- if (0 != btv->i2c_rc)
- return;
- i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
-}
-
-
/* read I2C */
int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
{
@@ -401,7 +356,11 @@ int __devinit init_bttv_i2c(struct bttv *btv)
strlcpy(btv->c.i2c_adap.name, "bt878",
sizeof(btv->c.i2c_adap.name));
btv->c.i2c_adap.id = I2C_HW_B_BT848; /* FIXME */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+ btv->c.i2c_adap.algo = (struct i2c_algorithm *)&bttv_algo;
+#else
btv->c.i2c_adap.algo = &bttv_algo;
+#endif
} else {
/* bt848 */
/* Prevents usage of invalid delay values */
@@ -418,21 +377,24 @@ int __devinit init_bttv_i2c(struct bttv *btv)
btv->c.i2c_adap.algo_data = &btv->i2c_algo;
}
btv->c.i2c_adap.owner = THIS_MODULE;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG;
- btv->c.i2c_adap.client_register = attach_inform;
+#endif
btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
"bt%d #%d [%s]", btv->id, btv->c.nr,
btv->use_i2c_hw ? "hw" : "sw");
- i2c_set_adapdata(&btv->c.i2c_adap, btv);
+ i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev);
btv->i2c_client.adapter = &btv->c.i2c_adap;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
if (bttv_tvcards[btv->c.type].no_video)
btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
if (bttv_tvcards[btv->c.type].has_dvb)
btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
+#endif
if (btv->use_i2c_hw) {
btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
@@ -442,7 +404,7 @@ int __devinit init_bttv_i2c(struct bttv *btv)
btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap);
}
if (0 == btv->i2c_rc && i2c_scan)
- do_i2c_scan(btv->c.name,&btv->i2c_client);
+ do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
return btv->i2c_rc;
}
diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h
index 3a065b8a4..6b7b62bd4 100644
--- a/linux/drivers/media/video/bt8xx/bttv.h
+++ b/linux/drivers/media/video/bt8xx/bttv.h
@@ -14,9 +14,10 @@
#ifndef _BTTV_H_
#define _BTTV_H_
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/i2c.h>
#include "compat.h"
+#include <media/v4l2-device.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
#include <media/i2c-addr.h>
@@ -182,6 +183,9 @@
#define BTTV_BOARD_VD012_X1 0x9a
#define BTTV_BOARD_VD012_X2 0x9b
#define BTTV_BOARD_IVCE8784 0x9c
+#define BTTV_BOARD_GEOVISION_GV800S 0x9d
+#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e
+#define BTTV_BOARD_PV183 0x9f
/* more card-specific defines */
@@ -195,6 +199,7 @@
struct bttv_core {
/* device structs */
+ struct v4l2_device v4l2_dev;
struct pci_dev *pci;
struct i2c_adapter i2c_adap;
struct list_head subs; /* struct bttv_sub_device */
@@ -202,7 +207,6 @@ struct bttv_core {
/* device config */
unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
unsigned int type; /* card type (pointer into tvcards[]) */
- char name[8]; /* dev name */
};
struct bttv;
@@ -237,6 +241,9 @@ struct tvcard {
unsigned int no_tda7432:1;
unsigned int needs_tvaudio:1;
unsigned int msp34xx_alt:1;
+ /* Note: currently no card definition needs to mark the presence
+ of a RDS saa6588 chip. If this is ever needed, then add a new
+ 'has_saa6588' bit here. */
unsigned int no_video:1; /* video pci function is unused */
unsigned int has_dvb:1;
@@ -354,7 +361,9 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
/* ---------------------------------------------------------- */
/* i2c */
-extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
+#define bttv_call_all(btv, o, f, args...) \
+ v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args)
+
extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char b2, int both);
diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h
index 20b1ad68a..65a8c1df1 100644
--- a/linux/drivers/media/video/bt8xx/bttvp.h
+++ b/linux/drivers/media/video/bt8xx/bttvp.h
@@ -32,7 +32,6 @@
#include <linux/wait.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
@@ -332,6 +331,7 @@ struct bttv {
unsigned int tuner_type; /* tuner chip type */
unsigned int tda9887_conf;
unsigned int svhs, dig;
+ unsigned int has_saa6588:1;
struct bttv_pll_info pll;
int triton1;
int gpioirq;
@@ -355,8 +355,8 @@ struct bttv {
int i2c_state, i2c_rc;
int i2c_done;
wait_queue_head_t i2c_queue;
- struct i2c_client *i2c_msp34xx_client;
- struct i2c_client *i2c_tvaudio_client;
+ struct v4l2_subdev *sd_msp34xx;
+ struct v4l2_subdev *sd_tvaudio;
/* video4linux (1) */
struct video_device *video_dev;
@@ -461,6 +461,11 @@ struct bttv {
__s32 crop_start;
};
+static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct bttv, c.v4l2_dev);
+}
+
/* our devices */
#define BTTV_MAX 32
extern unsigned int bttv_num;
diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c
index b6c328187..2516e80ed 100644
--- a/linux/drivers/media/video/cafe_ccic.c
+++ b/linux/drivers/media/video/cafe_ccic.c
@@ -11,6 +11,12 @@
*
* Written by Jonathan Corbet, corbet@lwn.net.
*
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this conversion is untested! Please contact the linux-media
+ * mailinglist if you can test this, together with the test results.
+ *
* This file may be distributed under the terms of the GNU General
* Public License, version 2.
*/
@@ -26,7 +32,7 @@
#include <linux/spinlock.h>
#include <linux/videodev2.h>
#include "compat.h"
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
#include <linux/device.h>
@@ -34,7 +40,6 @@
#include <linux/list.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
-#include <linux/debugfs.h>
#include <linux/jiffies.h>
#include <linux/vmalloc.h>
@@ -137,6 +142,7 @@ struct cafe_sio_buffer {
*/
struct cafe_camera
{
+ struct v4l2_device v4l2_dev;
enum cafe_state state;
unsigned long flags; /* Buffer status, mainly (dev_lock) */
int users; /* How many open FDs */
@@ -146,9 +152,10 @@ struct cafe_camera
* Subsystem structures.
*/
struct pci_dev *pdev;
- struct video_device v4ldev;
+ struct video_device vdev;
struct i2c_adapter i2c_adapter;
- struct i2c_client *sensor;
+ struct v4l2_subdev *sensor;
+ unsigned short sensor_addr;
unsigned char __iomem *regs;
struct list_head dev_list; /* link to other devices */
@@ -181,10 +188,6 @@ struct cafe_camera
/* Misc */
wait_queue_head_t smbus_wait; /* Waiting on i2c events */
wait_queue_head_t iowait; /* Waiting on frame data */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- struct dentry *dfs_regs;
- struct dentry *dfs_cam_regs;
-#endif
};
/*
@@ -196,6 +199,13 @@ struct cafe_camera
#define CF_DMA_ACTIVE 3 /* A frame is incoming */
#define CF_CONFIG_NEEDED 4 /* Must configure hardware */
+#define sensor_call(cam, o, f, args...) \
+ v4l2_subdev_call(cam->sensor, o, f, ##args)
+
+static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
+{
+ return container_of(dev, struct cafe_camera, v4l2_dev);
+}
/*
@@ -239,59 +249,7 @@ static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
/* ---------------------------------------------------------------------*/
-/*
- * We keep a simple list of known devices to search at open time.
- */
-static LIST_HEAD(cafe_dev_list);
-static DEFINE_MUTEX(cafe_dev_list_lock);
-
-static void cafe_add_dev(struct cafe_camera *cam)
-{
- mutex_lock(&cafe_dev_list_lock);
- list_add_tail(&cam->dev_list, &cafe_dev_list);
- mutex_unlock(&cafe_dev_list_lock);
-}
-
-static void cafe_remove_dev(struct cafe_camera *cam)
-{
- mutex_lock(&cafe_dev_list_lock);
- list_del(&cam->dev_list);
- mutex_unlock(&cafe_dev_list_lock);
-}
-
-static struct cafe_camera *cafe_find_dev(int minor)
-{
- struct cafe_camera *cam;
-
- mutex_lock(&cafe_dev_list_lock);
- list_for_each_entry(cam, &cafe_dev_list, dev_list) {
- if (cam->v4ldev.minor == minor)
- goto done;
- }
- cam = NULL;
- done:
- mutex_unlock(&cafe_dev_list_lock);
- return cam;
-}
-
-static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev)
-{
- struct cafe_camera *cam;
-
- mutex_lock(&cafe_dev_list_lock);
- list_for_each_entry(cam, &cafe_dev_list, dev_list) {
- if (cam->pdev == pdev)
- goto done;
- }
- cam = NULL;
- done:
- mutex_unlock(&cafe_dev_list_lock);
- return cam;
-}
-
-
-/* ------------------------------------------------------------------------ */
/*
* Device register I/O
*/
@@ -482,24 +440,11 @@ static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char rw, u8 command,
int size, union i2c_smbus_data *data)
{
- struct cafe_camera *cam = i2c_get_adapdata(adapter);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+ struct cafe_camera *cam = to_cam(v4l2_dev);
int ret = -EINVAL;
/*
- * Refuse to talk to anything but OV cam chips. We should
- * never even see an attempt to do so, but one never knows.
- */
-#if 0 /* client needs to talk during attach process */
- if (! cam->sensor) {
- cam_err(cam, "SMBUS xfer with no client\n");
- return -EINVAL;
- }
-#endif
- if (cam->sensor && addr != cam->sensor->addr) {
- cam_err(cam, "funky smbus addr %d\n", addr);
- return -EINVAL;
- }
- /*
* This interface would appear to only do byte data ops. OK
* it can do word too, but the cam chip has no use for that.
*/
@@ -537,38 +482,9 @@ static struct i2c_algorithm cafe_smbus_algo = {
};
/* Somebody is on the bus */
-static int cafe_cam_init(struct cafe_camera *cam);
static void cafe_ctlr_stop_dma(struct cafe_camera *cam);
static void cafe_ctlr_power_down(struct cafe_camera *cam);
-static int cafe_smbus_attach(struct i2c_client *client)
-{
- struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
-
- /*
- * Don't talk to chips we don't recognize.
- */
- if (client->driver->id == I2C_DRIVERID_OV7670) {
- cam->sensor = client;
- return cafe_cam_init(cam);
- }
- return -EINVAL;
-}
-
-static int cafe_smbus_detach(struct i2c_client *client)
-{
- struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
-
- if (cam->sensor == client) {
- cafe_ctlr_stop_dma(cam);
- cafe_ctlr_power_down(cam);
- cam_err(cam, "lost the sensor!\n");
- cam->sensor = NULL; /* Bummer, no camera */
- cam->state = S_NOTREADY;
- }
- return 0;
-}
-
static int cafe_smbus_setup(struct cafe_camera *cam)
{
struct i2c_adapter *adap = &cam->i2c_adapter;
@@ -577,12 +493,10 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
cafe_smbus_enable_irq(cam);
adap->id = I2C_HW_SMBUS_CAFE;
adap->owner = THIS_MODULE;
- adap->client_register = cafe_smbus_attach;
- adap->client_unregister = cafe_smbus_detach;
adap->algo = &cafe_smbus_algo;
strcpy(adap->name, "cafe_ccic");
adap->dev.parent = &cam->pdev->dev;
- i2c_set_adapdata(adap, cam);
+ i2c_set_adapdata(adap, &cam->v4l2_dev);
ret = i2c_add_adapter(adap);
if (ret)
printk(KERN_ERR "Unable to register cafe i2c adapter\n");
@@ -816,9 +730,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam)
* Control 1 is power down, set to 0 to operate.
*/
cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
-// mdelay(1); /* Marvell says 1ms will do it */
+/* mdelay(1); */ /* Marvell says 1ms will do it */
cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
-// mdelay(1); /* Enough? */
+/* mdelay(1); */ /* Enough? */
spin_unlock_irqrestore(&cam->dev_lock, flags);
msleep(5); /* Just to be sure */
}
@@ -840,23 +754,9 @@ static void cafe_ctlr_power_down(struct cafe_camera *cam)
* Communications with the sensor.
*/
-static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg)
-{
- struct i2c_client *sc = cam->sensor;
- int ret;
-
- if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL)
- return -EINVAL;
- ret = sc->driver->command(sc, cmd, arg);
- if (ret == -EPERM) /* Unsupported command */
- return 0;
- return ret;
-}
-
static int __cafe_cam_reset(struct cafe_camera *cam)
{
- int zero = 0;
- return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero);
+ return sensor_call(cam, core, reset, 0);
}
/*
@@ -876,14 +776,13 @@ static int cafe_cam_init(struct cafe_camera *cam)
if (ret)
goto out;
chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
- chip.match.addr = cam->sensor->addr;
- ret = __cafe_cam_cmd(cam, VIDIOC_DBG_G_CHIP_IDENT, &chip);
+ chip.match.addr = cam->sensor_addr;
+ ret = sensor_call(cam, core, g_chip_ident, &chip);
if (ret)
goto out;
cam->sensor_type = chip.ident;
-// if (cam->sensor->addr != OV7xx0_SID) {
if (cam->sensor_type != V4L2_IDENT_OV7670) {
- cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
+ cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
ret = -EINVAL;
goto out;
}
@@ -907,21 +806,21 @@ static int cafe_cam_set_flip(struct cafe_camera *cam)
memset(&ctrl, 0, sizeof(ctrl));
ctrl.id = V4L2_CID_VFLIP;
ctrl.value = flip;
- return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);
+ return sensor_call(cam, core, s_ctrl, &ctrl);
}
static int cafe_cam_configure(struct cafe_camera *cam)
{
struct v4l2_format fmt;
- int ret, zero = 0;
+ int ret;
if (cam->state != S_IDLE)
return -EINVAL;
fmt.fmt.pix = cam->pix_format;
- ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
+ ret = sensor_call(cam, core, init, 0);
if (ret == 0)
- ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt);
+ ret = sensor_call(cam, video, s_fmt, &fmt);
/*
* OV7670 does weird things if flip is set *before* format...
*/
@@ -1253,8 +1152,6 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
* Make sure it's something we can do. User pointers could be
* implemented without great pain, but that's not been done yet.
*/
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
if (req->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
/*
@@ -1318,9 +1215,7 @@ static int cafe_vidioc_querybuf(struct file *filp, void *priv,
int ret = -EINVAL;
mutex_lock(&cam->s_mutex);
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- goto out;
- if (buf->index < 0 || buf->index >= cam->n_sbufs)
+ if (buf->index >= cam->n_sbufs)
goto out;
*buf = cam->sb_bufs[buf->index].v4lbuf;
ret = 0;
@@ -1338,9 +1233,7 @@ static int cafe_vidioc_qbuf(struct file *filp, void *priv,
unsigned long flags;
mutex_lock(&cam->s_mutex);
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- goto out;
- if (buf->index < 0 || buf->index >= cam->n_sbufs)
+ if (buf->index >= cam->n_sbufs)
goto out;
sbuf = cam->sb_bufs + buf->index;
if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
@@ -1371,8 +1264,6 @@ static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
unsigned long flags;
mutex_lock(&cam->s_mutex);
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- goto out_unlock;
if (cam->state != S_STREAMING)
goto out_unlock;
if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
@@ -1481,11 +1372,8 @@ static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
static int cafe_v4l_open(struct file *filp)
{
- struct cafe_camera *cam;
+ struct cafe_camera *cam = video_drvdata(filp);
- cam = cafe_find_dev(video_devdata(filp)->minor);
- if (cam == NULL)
- return -ENODEV;
filp->private_data = cam;
mutex_lock(&cam->s_mutex);
@@ -1539,11 +1427,11 @@ static unsigned int cafe_v4l_poll(struct file *filp,
static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
struct v4l2_queryctrl *qc)
{
- struct cafe_camera *cam = filp->private_data;
+ struct cafe_camera *cam = priv;
int ret;
mutex_lock(&cam->s_mutex);
- ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);
+ ret = sensor_call(cam, core, queryctrl, qc);
mutex_unlock(&cam->s_mutex);
return ret;
}
@@ -1552,11 +1440,11 @@ static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
struct v4l2_control *ctrl)
{
- struct cafe_camera *cam = filp->private_data;
+ struct cafe_camera *cam = priv;
int ret;
mutex_lock(&cam->s_mutex);
- ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);
+ ret = sensor_call(cam, core, g_ctrl, ctrl);
mutex_unlock(&cam->s_mutex);
return ret;
}
@@ -1565,11 +1453,11 @@ static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
struct v4l2_control *ctrl)
{
- struct cafe_camera *cam = filp->private_data;
+ struct cafe_camera *cam = priv;
int ret;
mutex_lock(&cam->s_mutex);
- ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);
+ ret = sensor_call(cam, core, s_ctrl, ctrl);
mutex_unlock(&cam->s_mutex);
return ret;
}
@@ -1608,10 +1496,8 @@ static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
struct cafe_camera *cam = priv;
int ret;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
mutex_lock(&cam->s_mutex);
- ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt);
+ ret = sensor_call(cam, video, enum_fmt, fmt);
mutex_unlock(&cam->s_mutex);
return ret;
}
@@ -1624,7 +1510,7 @@ static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
int ret;
mutex_lock(&cam->s_mutex);
- ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);
+ ret = sensor_call(cam, video, try_fmt, fmt);
mutex_unlock(&cam->s_mutex);
return ret;
}
@@ -1733,7 +1619,7 @@ static int cafe_vidioc_g_parm(struct file *filp, void *priv,
int ret;
mutex_lock(&cam->s_mutex);
- ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);
+ ret = sensor_call(cam, video, g_parm, parms);
mutex_unlock(&cam->s_mutex);
parms->parm.capture.readbuffers = n_dma_bufs;
return ret;
@@ -1746,20 +1632,52 @@ static int cafe_vidioc_s_parm(struct file *filp, void *priv,
int ret;
mutex_lock(&cam->s_mutex);
- ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);
+ ret = sensor_call(cam, video, s_parm, parms);
mutex_unlock(&cam->s_mutex);
parms->parm.capture.readbuffers = n_dma_bufs;
return ret;
}
+static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct cafe_camera *cam = priv;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (v4l2_chip_match_host(&chip->match)) {
+ chip->ident = V4L2_IDENT_CAFE;
+ return 0;
+ }
+ return sensor_call(cam, core, g_chip_ident, chip);
+}
-static void cafe_v4l_dev_release(struct video_device *vd)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cafe_vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
{
- struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
+ struct cafe_camera *cam = priv;
- kfree(cam);
+ if (v4l2_chip_match_host(&reg->match)) {
+ reg->val = cafe_reg_read(cam, reg->reg);
+ reg->size = 4;
+ return 0;
+ }
+ return sensor_call(cam, core, g_register, reg);
}
+static int cafe_vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct cafe_camera *cam = priv;
+
+ if (v4l2_chip_match_host(&reg->match)) {
+ cafe_reg_write(cam, reg->reg, reg->val);
+ return 0;
+ }
+ return sensor_call(cam, core, s_register, reg);
+}
+#endif
/*
* This template device holds all of those v4l2 methods; we
@@ -1797,6 +1715,11 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
.vidioc_s_ctrl = cafe_vidioc_s_ctrl,
.vidioc_g_parm = cafe_vidioc_g_parm,
.vidioc_s_parm = cafe_vidioc_s_parm,
+ .vidioc_g_chip_ident = cafe_vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = cafe_vidioc_g_register,
+ .vidioc_s_register = cafe_vidioc_s_register,
+#endif
};
static struct video_device cafe_v4l_template = {
@@ -1807,15 +1730,10 @@ static struct video_device cafe_v4l_template = {
.fops = &cafe_v4l_fops,
.ioctl_ops = &cafe_v4l_ioctl_ops,
- .release = cafe_v4l_dev_release,
+ .release = video_device_release_empty,
};
-
-
-
-
-
/* ---------------------------------------------------------------------- */
/*
* Interrupt handler stuff
@@ -1969,127 +1887,6 @@ static irqreturn_t cafe_irq(int irq, void *data)
/* -------------------------------------------------------------------------- */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/*
- * Debugfs stuff.
- */
-
-static char cafe_debug_buf[1024];
-static struct dentry *cafe_dfs_root;
-
-static void cafe_dfs_setup(void)
-{
- cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL);
- if (IS_ERR(cafe_dfs_root)) {
- cafe_dfs_root = NULL; /* Never mind */
- printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n");
- }
-}
-
-static void cafe_dfs_shutdown(void)
-{
- if (cafe_dfs_root)
- debugfs_remove(cafe_dfs_root);
-}
-
-static int cafe_dfs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t cafe_dfs_read_regs(struct file *file,
- char __user *buf, size_t count, loff_t *ppos)
-{
- struct cafe_camera *cam = file->private_data;
- char *s = cafe_debug_buf;
- int offset;
-
- for (offset = 0; offset < 0x44; offset += 4)
- s += sprintf(s, "%02x: %08x\n", offset,
- cafe_reg_read(cam, offset));
- for (offset = 0x88; offset <= 0x90; offset += 4)
- s += sprintf(s, "%02x: %08x\n", offset,
- cafe_reg_read(cam, offset));
- for (offset = 0xb4; offset <= 0xbc; offset += 4)
- s += sprintf(s, "%02x: %08x\n", offset,
- cafe_reg_read(cam, offset));
- for (offset = 0x3000; offset <= 0x300c; offset += 4)
- s += sprintf(s, "%04x: %08x\n", offset,
- cafe_reg_read(cam, offset));
- return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
- s - cafe_debug_buf);
-}
-
-static const struct file_operations cafe_dfs_reg_ops = {
- .owner = THIS_MODULE,
- .read = cafe_dfs_read_regs,
- .open = cafe_dfs_open
-};
-
-static ssize_t cafe_dfs_read_cam(struct file *file,
- char __user *buf, size_t count, loff_t *ppos)
-{
- struct cafe_camera *cam = file->private_data;
- char *s = cafe_debug_buf;
- int offset;
-
- if (! cam->sensor)
- return -EINVAL;
- for (offset = 0x0; offset < 0x8a; offset++)
- {
- u8 v;
-
- cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v);
- s += sprintf(s, "%02x: %02x\n", offset, v);
- }
- return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
- s - cafe_debug_buf);
-}
-
-static const struct file_operations cafe_dfs_cam_ops = {
- .owner = THIS_MODULE,
- .read = cafe_dfs_read_cam,
- .open = cafe_dfs_open
-};
-
-
-
-static void cafe_dfs_cam_setup(struct cafe_camera *cam)
-{
- char fname[40];
-
- if (!cafe_dfs_root)
- return;
- sprintf(fname, "regs-%d", cam->v4ldev.num);
- cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
- cam, &cafe_dfs_reg_ops);
- sprintf(fname, "cam-%d", cam->v4ldev.num);
- cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
- cam, &cafe_dfs_cam_ops);
-}
-
-
-static void cafe_dfs_cam_shutdown(struct cafe_camera *cam)
-{
- if (! IS_ERR(cam->dfs_regs))
- debugfs_remove(cam->dfs_regs);
- if (! IS_ERR(cam->dfs_cam_regs))
- debugfs_remove(cam->dfs_cam_regs);
-}
-
-#else
-
-#define cafe_dfs_setup()
-#define cafe_dfs_shutdown()
-#define cafe_dfs_cam_setup(cam)
-#define cafe_dfs_cam_shutdown(cam)
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-
-
-
-/* ------------------------------------------------------------------------*/
/*
* PCI interface stuff.
*/
@@ -2107,6 +1904,10 @@ static int cafe_pci_probe(struct pci_dev *pdev,
cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
if (cam == NULL)
goto out;
+ ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
+ if (ret)
+ goto out_free;
+
mutex_init(&cam->s_mutex);
mutex_lock(&cam->s_mutex);
spin_lock_init(&cam->dev_lock);
@@ -2125,14 +1926,14 @@ static int cafe_pci_probe(struct pci_dev *pdev,
*/
ret = pci_enable_device(pdev);
if (ret)
- goto out_free;
+ goto out_unreg;
pci_set_master(pdev);
ret = -EIO;
cam->regs = pci_iomap(pdev, 0, 0);
if (! cam->regs) {
printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
- goto out_free;
+ goto out_unreg;
}
ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
if (ret)
@@ -2152,17 +1953,31 @@ static int cafe_pci_probe(struct pci_dev *pdev,
ret = cafe_smbus_setup(cam);
if (ret)
goto out_freeirq;
+
+ cam->sensor_addr = 0x42;
+ cam->sensor = v4l2_i2c_new_subdev(&cam->i2c_adapter,
+ "ov7670", "ov7670", cam->sensor_addr);
+ if (cam->sensor == NULL) {
+ ret = -ENODEV;
+ goto out_smbus;
+ }
+ ret = cafe_cam_init(cam);
+ if (ret)
+ goto out_smbus;
+
/*
* Get the v4l2 setup done.
*/
mutex_lock(&cam->s_mutex);
- cam->v4ldev = cafe_v4l_template;
- cam->v4ldev.debug = 0;
-// cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
- cam->v4ldev.parent = &pdev->dev;
- ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
+ cam->vdev = cafe_v4l_template;
+ cam->vdev.debug = 0;
+/* cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
if (ret)
goto out_smbus;
+ video_set_drvdata(&cam->vdev, cam);
+
/*
* If so requested, try to get our DMA buffers now.
*/
@@ -2172,21 +1987,21 @@ static int cafe_pci_probe(struct pci_dev *pdev,
" will try again later.");
}
- cafe_dfs_cam_setup(cam);
mutex_unlock(&cam->s_mutex);
- cafe_add_dev(cam);
return 0;
- out_smbus:
+out_smbus:
cafe_smbus_shutdown(cam);
- out_freeirq:
+out_freeirq:
cafe_ctlr_power_down(cam);
free_irq(pdev->irq, cam);
- out_iounmap:
+out_iounmap:
pci_iounmap(pdev, cam->regs);
- out_free:
+out_free:
+ v4l2_device_unregister(&cam->v4l2_dev);
+out_unreg:
kfree(cam);
- out:
+out:
return ret;
}
@@ -2197,25 +2012,23 @@ static int cafe_pci_probe(struct pci_dev *pdev,
static void cafe_shutdown(struct cafe_camera *cam)
{
/* FIXME: Make sure we take care of everything here */
- cafe_dfs_cam_shutdown(cam);
if (cam->n_sbufs > 0)
/* What if they are still mapped? Shouldn't be, but... */
cafe_free_sio_buffers(cam);
- cafe_remove_dev(cam);
cafe_ctlr_stop_dma(cam);
cafe_ctlr_power_down(cam);
cafe_smbus_shutdown(cam);
cafe_free_dma_bufs(cam);
free_irq(cam->pdev->irq, cam);
pci_iounmap(cam->pdev, cam->regs);
- video_unregister_device(&cam->v4ldev);
- /* kfree(cam); done in v4l_release () */
+ video_unregister_device(&cam->vdev);
}
static void cafe_pci_remove(struct pci_dev *pdev)
{
- struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+ struct cafe_camera *cam = to_cam(v4l2_dev);
if (cam == NULL) {
printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
@@ -2225,6 +2038,8 @@ static void cafe_pci_remove(struct pci_dev *pdev)
if (cam->users > 0)
cam_warn(cam, "Removing a device with users!\n");
cafe_shutdown(cam);
+ v4l2_device_unregister(&cam->v4l2_dev);
+ kfree(cam);
/* No unlock - it no longer exists */
}
@@ -2235,7 +2050,8 @@ static void cafe_pci_remove(struct pci_dev *pdev)
*/
static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+ struct cafe_camera *cam = to_cam(v4l2_dev);
int ret;
enum cafe_state cstate;
@@ -2253,7 +2069,8 @@ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int cafe_pci_resume(struct pci_dev *pdev)
{
- struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+ struct cafe_camera *cam = to_cam(v4l2_dev);
int ret = 0;
ret = pci_restore_state(pdev);
@@ -2314,13 +2131,11 @@ static int __init cafe_init(void)
printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
CAFE_VERSION);
- cafe_dfs_setup();
ret = pci_register_driver(&cafe_pci_driver);
if (ret) {
printk(KERN_ERR "Unable to register cafe_ccic driver\n");
goto out;
}
- request_module("ov7670"); /* FIXME want something more general */
ret = 0;
out:
@@ -2331,7 +2146,6 @@ static int __init cafe_init(void)
static void __exit cafe_exit(void)
{
pci_unregister_driver(&cafe_pci_driver);
- cafe_dfs_shutdown();
}
module_init(cafe_init);
diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c
index 9c25894fd..d4099f531 100644
--- a/linux/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c
@@ -37,6 +37,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/videodev.h>
#include <media/v4l2-ioctl.h>
#include "cpia2.h"
diff --git a/linux/drivers/media/video/cs53l32a.c b/linux/drivers/media/video/cs53l32a.c
index c8b5fa157..4745fd21c 100644
--- a/linux/drivers/media/video/cs53l32a.c
+++ b/linux/drivers/media/video/cs53l32a.c
@@ -29,7 +29,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
#include "compat.h"
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
@@ -42,9 +42,11 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
+#endif
/* ----------------------------------------------------------------------- */
@@ -123,11 +125,6 @@ static int cs53l32a_log_status(struct v4l2_subdev *sd)
return 0;
}
-static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
@@ -225,7 +222,6 @@ MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs53l32a",
- .command = cs53l32a_command,
.remove = cs53l32a_remove,
.probe = cs53l32a_probe,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
diff --git a/linux/drivers/media/video/cx18/Kconfig b/linux/drivers/media/video/cx18/Kconfig
index 8940b5387..e8a50a611 100644
--- a/linux/drivers/media/video/cx18/Kconfig
+++ b/linux/drivers/media/video/cx18/Kconfig
@@ -9,7 +9,7 @@ config VIDEO_CX18
select VIDEO_CX2341X
select VIDEO_CS5345
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
---help---
This is a video4linux driver for Conexant cx23418 based
PCI combo video recorder devices.
diff --git a/linux/drivers/media/video/cx18/cx18-audio.c b/linux/drivers/media/video/cx18/cx18-audio.c
index ccd170887..bb5c5165d 100644
--- a/linux/drivers/media/video/cx18/cx18-audio.c
+++ b/linux/drivers/media/video/cx18/cx18-audio.c
@@ -24,6 +24,7 @@
#include "cx18-driver.h"
#include "cx18-io.h"
#include "cx18-cards.h"
+#include "cx18-audio.h"
#define CX18_AUDIO_ENABLE 0xc72014
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index cf256a999..21f4be839 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -292,23 +292,29 @@ void cx18_av_std_setup(struct cx18 *cx)
*
* vsync: always 6 half-lines of vsync pulses
* vactive: half lines of active video
- * vblank656: half lines, after line 3, of blanked video
- * vblank: half lines, after line 9, of blanked video
+ * vblank656: half lines, after line 3/mid-266, of blanked video
+ * vblank: half lines, after line 9/272, of blanked video
*
+ * As far as I can tell:
* vblank656 starts counting from the falling edge of the first
- * vsync pulse (start of line 4)
+ * vsync pulse (start of line 4 or mid-266)
* vblank starts counting from the after the 6 vsync pulses and
- * 6 equalization pulses (start of line 10)
+ * 6 or 5 equalization pulses (start of line 10 or 272)
*
* For 525 line systems the driver will extract VBI information
- * from lines 10 through 21. To avoid the EAV RP code from
- * toggling at the start of hblank at line 22, where sliced VBI
- * data from line 21 is stuffed, also treat line 22 as blanked.
+ * from lines 10-21 and lines 273-284.
*/
- vblank656 = 38; /* lines 4 through 22 */
- vblank = 26; /* lines 10 through 22 */
- vactive = 481; /* lines 23 through 262.5 */
+ vblank656 = 38; /* lines 4 - 22 & 266 - 284 */
+ vblank = 26; /* lines 10 - 22 & 272 - 284 */
+ vactive = 481; /* lines 23 - 263 & 285 - 525 */
+ /*
+ * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is
+ * is 858 pixels = 720 active + 138 blanking. The Hsync leading
+ * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the
+ * end of active video, leaving 122 pixels of hblank to ignore
+ * before active video starts.
+ */
hactive = 720;
hblank = 122;
luma_lpf = 1;
@@ -867,8 +873,22 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
- Vlines = pix->height + (is_50Hz ? 4 : 7);
+ /*
+ * This adjustment reflects the excess of vactive, set in
+ * cx18_av_std_setup(), above standard values:
+ *
+ * 480 + 1 for 60 Hz systems
+ * 576 + 4 for 50 Hz systems
+ */
+ Vlines = pix->height + (is_50Hz ? 4 : 1);
+ /*
+ * Invalid height and width scaling requests are:
+ * 1. width less than 1/16 of the source width
+ * 2. width greater than the source width
+ * 3. height less than 1/8 of the source height
+ * 4. height greater than the source height
+ */
if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
(Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h
index fd0df4151..2687a2c91 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.h
+++ b/linux/drivers/media/video/cx18/cx18-av-core.h
@@ -89,16 +89,21 @@ struct cx18_av_state {
/*
* The VBI slicer starts operating and counting lines, begining at
- * slicer line count of 1, at D lines after the deassertion of VRESET
- * This staring field line, S, is 6 or 10 for 625 or 525 line systems.
- * Sliced ancillary data captured on VBI slicer line M is sent at the
- * beginning of the next VBI slicer line, VBI slicer line count N = M+1.
- * Thus when the VBI slicer reports a VBI slicer line number with
- * ancillary data, the IDID0 byte indicates VBI slicer line N.
- * The actual field line that the captured data comes from is
+ * slicer line count of 1, at D lines after the deassertion of VRESET.
+ * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525
+ * line systems respectively. Sliced ancillary data captured on VBI
+ * slicer line M is inserted after the VBI slicer is done with line M,
+ * when VBI slicer line count is N = M+1. Thus when the VBI slicer
+ * reports a VBI slicer line number with ancillary data, the IDID0 byte
+ * indicates VBI slicer line N. The actual field line that the captured
+ * data comes from is
+ *
* L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
*
+ * L is the line in the field, not frame, from which the VBI data came.
+ * N is the line reported by the slicer in the ancillary data.
* D is the slicer_line_delay value programmed into register 0x47f.
+ * S is 6 for 625 line systems or 10 for 525 line systems
* (S+D-2) is the slicer_line_offset used to convert slicer reported
* line counts to actual field lines.
*/
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
index 43267d1af..27699839b 100644
--- a/linux/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -142,7 +142,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
0, V4L2_SLICED_WSS_625, 0, /* 4 */
V4L2_SLICED_CAPTION_525, /* 6 */
- V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 - unlike cx25840 */
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
0, 0, 0, 0
};
int is_pal = !(state->std & V4L2_STD_525_60);
@@ -243,7 +243,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
lcr[i] |= 6 << (4 * x);
break;
case V4L2_SLICED_VPS:
- lcr[i] |= 7 << (4 * x); /*'840 differs*/
+ lcr[i] |= 9 << (4 * x);
break;
}
}
@@ -301,7 +301,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
sdid = V4L2_SLICED_CAPTION_525;
err = !odd_parity(p[0]) || !odd_parity(p[1]);
break;
- case 7: /* Differs from cx25840 */
+ case 9:
sdid = V4L2_SLICED_VPS;
if (decode_vps(p, p) != 0)
err = 1;
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
index 925e01fdb..82fc2f9d4 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.c
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -166,15 +166,26 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
return 0;
}
-static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
+static int cx18_setup_vbi_fmt(struct cx18 *cx,
+ enum v4l2_mpeg_stream_vbi_fmt fmt,
+ enum v4l2_mpeg_stream_type type)
{
if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
return -EINVAL;
if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
- /* First try to allocate sliced VBI buffers if needed. */
- if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
+ if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
+ type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+ /* We don't do VBI insertion aside from IVTV format in a PS */
+ cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
+ CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
+ "the MPEG stream\n");
+ return 0;
+ }
+
+ /* Allocate sliced VBI buffers if needed. */
+ if (cx->vbi.sliced_mpeg_data[0] == NULL) {
int i;
for (i = 0; i < CX18_VBI_FRAMES; i++) {
@@ -185,19 +196,27 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
kfree(cx->vbi.sliced_mpeg_data[i]);
cx->vbi.sliced_mpeg_data[i] = NULL;
}
+ cx->vbi.insert_mpeg =
+ V4L2_MPEG_STREAM_VBI_FMT_NONE;
+ CX18_WARN("Unable to allocate buffers for "
+ "sliced VBI data insertion\n");
return -ENOMEM;
}
}
}
cx->vbi.insert_mpeg = fmt;
+ CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
+ "when sliced VBI is enabled\n");
- if (cx->vbi.insert_mpeg == 0)
- return 0;
- /* Need sliced data for mpeg insertion */
+ /*
+ * If our current settings have no lines set for capture, store a valid,
+ * default set of service lines to capture, in our current settings.
+ */
if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
if (cx->is_60hz)
- cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+ cx->vbi.sliced_in->service_set =
+ V4L2_SLICED_CAPTION_525;
else
cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
@@ -284,8 +303,11 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
priv.cx = cx;
priv.s = &cx->streams[id->type];
err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
- if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
- err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+ if (!err &&
+ (cx->params.stream_vbi_fmt != p.stream_vbi_fmt ||
+ cx->params.stream_type != p.stream_type))
+ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt,
+ p.stream_type);
cx->params = p;
cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
idx = p.audio_properties & 0x03;
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index 8f294f436..f688ec7db 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -273,8 +273,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
u8 eedata[256];
memset(&c, 0, sizeof(c));
- strncpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
- c.name[sizeof(c.name)-1] = '\0';
+ strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
c.adapter = &cx->i2c_adap[0];
c.addr = 0xA0 >> 1;
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index 0605c2d83..7c1db9c18 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -413,9 +413,8 @@ static void cx18_vbi_setup(struct cx18_stream *s)
* 0x90 (Task HorizontalBlank)
* 0xd0 (Task EvenField HorizontalBlank)
*
- * We have set the digitzer to consider the first active line
- * as part of VerticalBlank as well so we don't have to look for
- * these problem codes nor lose the last line of sliced data.
+ * We have set the digitzer such that we don't have to worry
+ * about these problem codes.
*/
data[4] = 0xB0F0B0F0;
/*
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c
index a81fe2e98..c2aef4add 100644
--- a/linux/drivers/media/video/cx18/cx18-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-vbi.c
@@ -88,6 +88,8 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
size = 4 + ((43 * line + 3) & ~3);
} else {
memcpy(dst + sd, "itv0", 4);
+ cpu_to_le32s(&linemask[0]);
+ cpu_to_le32s(&linemask[1]);
memcpy(dst + sd + 4, &linemask[0], 8);
size = 12 + ((43 * line + 3) & ~3);
}
@@ -103,54 +105,72 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
/* Compress raw VBI format, removes leading SAV codes and surplus space
after the frame. Returns new compressed size. */
-static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
+static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size)
{
u32 line_size = vbi_active_samples;
u32 lines = cx->vbi.count * 2;
- u8 sav1 = raw_vbi_sav_rp[0];
- u8 sav2 = raw_vbi_sav_rp[1];
u8 *q = buf;
u8 *p;
int i;
+ /* Skip the header */
+ buf += hdr_size;
+
for (i = 0; i < lines; i++) {
p = buf + i * line_size;
/* Look for SAV code */
if (p[0] != 0xff || p[1] || p[2] ||
- (p[3] != sav1 && p[3] != sav2))
+ (p[3] != raw_vbi_sav_rp[0] &&
+ p[3] != raw_vbi_sav_rp[1]))
break;
- memcpy(q, p + 4, line_size - 4);
- q += line_size - 4;
+ if (i == lines - 1) {
+ /* last line is hdr_size bytes short - extrapolate it */
+ memcpy(q, p + 4, line_size - 4 - hdr_size);
+ q += line_size - 4 - hdr_size;
+ p += line_size - hdr_size - 1;
+ memset(q, (int) *p, hdr_size);
+ } else {
+ memcpy(q, p + 4, line_size - 4);
+ q += line_size - 4;
+ }
}
return lines * (line_size - 4);
}
-
-/* Compressed VBI format, all found sliced blocks put next to one another
- Returns new compressed size */
-static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
- u32 size, u8 eav)
+static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size,
+ const u32 hdr_size)
{
struct v4l2_decode_vbi_line vbi;
int i;
+ u32 line = 0;
u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
: vbi_hblank_samples_50Hz;
/* find the first valid line */
- for (i = 0; i < size; i++, buf++) {
- if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == eav)
+ for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) {
+ if (buf[0] == 0xff && !buf[1] && !buf[2] &&
+ (buf[3] == sliced_vbi_eav_rp[0] ||
+ buf[3] == sliced_vbi_eav_rp[1]))
break;
}
- size -= i;
+ /*
+ * The last line is short by hdr_size bytes, but for the remaining
+ * checks against size, we pretend that it is not, by counting the
+ * header bytes we knowingly skipped
+ */
+ size -= (i - hdr_size);
if (size < line_size)
return line;
+
for (i = 0; i < size / line_size; i++) {
u8 *p = buf + i * line_size;
/* Look for EAV code */
- if (p[0] != 0xff || p[1] || p[2] || p[3] != eav)
+ if (p[0] != 0xff || p[1] || p[2] ||
+ (p[3] != sliced_vbi_eav_rp[0] &&
+ p[3] != sliced_vbi_eav_rp[1]))
continue;
vbi.p = p + 4;
v4l2_subdev_call(cx->sd_av, video, decode_vbi_line, &vbi);
@@ -168,8 +188,17 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
int streamtype)
{
+ /*
+ * The CX23418 provides a 12 byte header in its raw VBI buffers to us:
+ * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp]
+ */
+ struct vbi_data_hdr {
+ __be32 magic;
+ __be32 unknown;
+ __be32 pts;
+ } *hdr = (struct vbi_data_hdr *) buf->buf;
+
u8 *p = (u8 *) buf->buf;
- u32 *q = (u32 *) buf->buf;
u32 size = buf->bytesused;
u32 pts;
int lines;
@@ -178,33 +207,17 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
return;
/*
- * The CX23418 sends us data that is 32 bit LE swapped, but we want
- * the raw VBI bytes in the order they were in the raster line
+ * The CX23418 sends us data that is 32 bit little-endian swapped,
+ * but we want the raw VBI bytes in the order they were in the raster
+ * line. This has a side effect of making the header big endian
*/
cx18_buf_swap(buf);
- /*
- * The CX23418 provides a 12 byte header in it's raw VBI buffers to us:
- * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp?]
- */
-
/* Raw VBI data */
if (cx18_raw_vbi(cx)) {
- u8 type;
-
- /*
- * We've set up to get a frame's worth of VBI data at a time.
- * Skip 12 bytes of header prefixing the first field.
- */
- size -= 12;
- memcpy(p, &buf->buf[12], size);
- type = p[3];
- /* Extrapolate the last 12 bytes of the frame's last line */
- memset(&p[size], (int) p[size - 1], 12);
- size += 12;
-
- size = buf->bytesused = compress_raw_buf(cx, p, size);
+ size = buf->bytesused =
+ compress_raw_buf(cx, p, size, sizeof(struct vbi_data_hdr));
/*
* Hack needed for compatibility with old VBI software.
@@ -218,26 +231,11 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
/* Sliced VBI data with data insertion */
- pts = (be32_to_cpu(q[0] == 0x3fffffff)) ? be32_to_cpu(q[2]) : 0;
+ pts = (be32_to_cpu(hdr->magic) == 0x3fffffff) ? be32_to_cpu(hdr->pts)
+ : 0;
- /*
- * For calls to compress_sliced_buf(), ensure there are an integral
- * number of lines by shifting the real data up over the 12 bytes header
- * that got stuffed in.
- * FIXME - there's a smarter way to do this with pointers, but for some
- * reason I can't get it to work correctly right now.
- */
- memcpy(p, &buf->buf[12], size-12);
+ lines = compress_sliced_buf(cx, p, size, sizeof(struct vbi_data_hdr));
- /* first field */
- lines = compress_sliced_buf(cx, 0, p, size / 2, sliced_vbi_eav_rp[0]);
- /*
- * second field
- * In case the second half does not always begin at the exact address,
- * start a bit earlier (hence 32).
- */
- lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
- size / 2 + 32, sliced_vbi_eav_rp[1]);
/* always return at least one empty line */
if (lines == 0) {
cx->vbi.sliced_data[0].id = 0;
diff --git a/linux/drivers/media/video/cx231xx/Kconfig b/linux/drivers/media/video/cx231xx/Kconfig
new file mode 100644
index 000000000..477d4ab5e
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/Kconfig
@@ -0,0 +1,35 @@
+config VIDEO_CX231XX
+ tristate "Conexant cx231xx USB video capture support"
+ depends on VIDEO_DEV && I2C && INPUT
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ select VIDEOBUF_VMALLOC
+ select VIDEO_CX25840
+
+ ---help---
+ This is a video4linux driver for Conexant 231xx USB based TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx231xx
+
+config VIDEO_CX231XX_ALSA
+ tristate "Conexant Cx231xx ALSA audio module"
+ depends on VIDEO_CX231XX && SND
+ select SND_PCM
+
+ ---help---
+ This is an ALSA driver for Cx231xx USB based TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx231xx-alsa
+
+config VIDEO_CX231XX_DVB
+ tristate "DVB/ATSC Support for Cx231xx based TV cards"
+ depends on VIDEO_CX231XX && DVB_CORE
+ select VIDEOBUF_DVB
+ select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE
+
+ ---help---
+ This adds support for DVB cards based on the
+ Conexant cx231xx chips.
diff --git a/linux/drivers/media/video/cx231xx/Makefile b/linux/drivers/media/video/cx231xx/Makefile
new file mode 100644
index 000000000..755dd0ce6
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/Makefile
@@ -0,0 +1,14 @@
+cx231xx-objs := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
+ cx231xx-avcore.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+
+cx231xx-alsa-objs := cx231xx-audio.o
+
+obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o
+obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o
+obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-audio.c b/linux/drivers/media/video/cx231xx/cx231xx-audio.c
new file mode 100644
index 000000000..0f7fb3ca7
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-audio.c
@@ -0,0 +1,667 @@
+/*
+ * Conexant Cx231xx audio extension
+ *
+ * Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ * Based on em28xx driver
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include "compat.h"
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <media/v4l2-common.h>
+#include "cx231xx.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+#define dprintk(fmt, arg...) do { \
+ if (debug) \
+ printk(KERN_INFO "cx231xx-audio %s: " fmt, \
+ __func__, ##arg); \
+ } while (0)
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+
+static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
+{
+ int i;
+
+ dprintk("Stopping isoc\n");
+
+ for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+ if (dev->adev.urb[i]) {
+ if (!irqs_disabled())
+ usb_kill_urb(dev->adev.urb[i]);
+ else
+ usb_unlink_urb(dev->adev.urb[i]);
+
+ usb_free_urb(dev->adev.urb[i]);
+ dev->adev.urb[i] = NULL;
+
+ kfree(dev->adev.transfer_buffer[i]);
+ dev->adev.transfer_buffer[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void cx231xx_audio_isocirq(struct urb *urb, struct pt_regs *regs)
+#else
+static void cx231xx_audio_isocirq(struct urb *urb)
+#endif
+{
+ struct cx231xx *dev = urb->context;
+ int i;
+ unsigned int oldptr;
+#ifdef NO_PCM_LOCK
+ unsigned long flags;
+#endif
+ int period_elapsed = 0;
+ int status;
+ unsigned char *cp;
+ unsigned int stride;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ snd_pcm_substream_t *substream;
+ snd_pcm_runtime_t *runtime;
+#else
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+#endif
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ dprintk("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ if (dev->adev.capture_pcm_substream) {
+ substream = dev->adev.capture_pcm_substream;
+ runtime = substream->runtime;
+ stride = runtime->frame_bits >> 3;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int length = urb->iso_frame_desc[i].actual_length /
+ stride;
+ cp = (unsigned char *)urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+
+ if (!length)
+ continue;
+
+#ifdef NO_PCM_LOCK
+ spin_lock_irqsave(&dev->adev.slock, flags);
+#endif
+ oldptr = dev->adev.hwptr_done_capture;
+ if (oldptr + length >= runtime->buffer_size) {
+ unsigned int cnt;
+
+ cnt = runtime->buffer_size - oldptr;
+ memcpy(runtime->dma_area + oldptr * stride, cp,
+ cnt * stride);
+ memcpy(runtime->dma_area, cp + cnt * stride,
+ length * stride - cnt * stride);
+ } else {
+ memcpy(runtime->dma_area + oldptr * stride, cp,
+ length * stride);
+ }
+
+#ifndef NO_PCM_LOCK
+ snd_pcm_stream_lock(substream);
+#endif
+
+ dev->adev.hwptr_done_capture += length;
+ if (dev->adev.hwptr_done_capture >=
+ runtime->buffer_size)
+ dev->adev.hwptr_done_capture -=
+ runtime->buffer_size;
+
+ dev->adev.capture_transfer_done += length;
+ if (dev->adev.capture_transfer_done >=
+ runtime->period_size) {
+ dev->adev.capture_transfer_done -=
+ runtime->period_size;
+ period_elapsed = 1;
+ }
+#ifdef NO_PCM_LOCK
+ spin_unlock_irqrestore(&dev->adev.slock, flags);
+#else
+ snd_pcm_stream_unlock(substream);
+#endif
+ }
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+ }
+ urb->status = 0;
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
+ status);
+ }
+ return;
+}
+
+static int cx231xx_init_audio_isoc(struct cx231xx *dev)
+{
+ int i, errCode;
+ int sb_size;
+
+ cx231xx_info("%s: Starting AUDIO transfers\n", __func__);
+
+ sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
+
+ for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+ struct urb *urb;
+ int j, k;
+
+ dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+ if (!dev->adev.transfer_buffer[i])
+ return -ENOMEM;
+
+ memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
+ urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+ if (!urb) {
+ cx231xx_errdev("usb_alloc_urb failed!\n");
+ for (j = 0; j < i; j++) {
+ usb_free_urb(dev->adev.urb[j]);
+ kfree(dev->adev.transfer_buffer[j]);
+ }
+ return -ENOMEM;
+ }
+
+ urb->dev = dev->udev;
+ urb->context = dev;
+ urb->pipe = usb_rcvisocpipe(dev->udev,
+ dev->adev.end_point_addr);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = dev->adev.transfer_buffer[i];
+ urb->interval = 1;
+ urb->complete = cx231xx_audio_isocirq;
+ urb->number_of_packets = CX231XX_NUM_AUDIO_PACKETS;
+ urb->transfer_buffer_length = sb_size;
+
+ for (j = k = 0; j < CX231XX_NUM_AUDIO_PACKETS;
+ j++, k += dev->adev.max_pkt_size) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length = dev->adev.max_pkt_size;
+ }
+ dev->adev.urb[i] = urb;
+ }
+
+ for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+ errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+ if (errCode < 0) {
+ cx231xx_isoc_audio_deinit(dev);
+ return errCode;
+ }
+ }
+
+ return errCode;
+}
+
+static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg)
+{
+ dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
+ "stop" : "start");
+
+ switch (cmd) {
+ case CX231XX_CAPTURE_STREAM_EN:
+ if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
+ dev->adev.capture_stream = STREAM_ON;
+ cx231xx_init_audio_isoc(dev);
+ } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
+ dev->adev.capture_stream = STREAM_OFF;
+ cx231xx_isoc_audio_deinit(dev);
+ } else {
+ cx231xx_errdev("An underrun very likely occurred. "
+ "Ignoring it.\n");
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
+#else
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+#endif
+{
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ snd_pcm_runtime_t *runtime = subs->runtime;
+#else
+ struct snd_pcm_runtime *runtime = subs->runtime;
+#endif
+
+ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static snd_pcm_hardware_t snd_cx231xx_hw_capture = {
+#else
+static struct snd_pcm_hardware snd_cx231xx_hw_capture = {
+#endif
+ .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
+ .period_bytes_min = 64, /* 12544/2, */
+ .period_bytes_max = 12544,
+ .periods_min = 2,
+ .periods_max = 98, /* 12544, */
+};
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static int snd_cx231xx_capture_open(snd_pcm_substream_t *substream)
+#else
+static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
+#endif
+{
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ snd_pcm_runtime_t *runtime = substream->runtime;
+#else
+ struct snd_pcm_runtime *runtime = substream->runtime;
+#endif
+ int ret = 0;
+
+ dprintk("opening device and trying to acquire exclusive lock\n");
+
+ if (!dev) {
+ cx231xx_errdev("BUG: cx231xx can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+
+ /* Sets volume, mute, etc */
+ dev->mute = 0;
+
+ /* set alternate setting for audio interface */
+ /* 1 - 48000 samples per sec */
+ ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
+ if (ret < 0) {
+ cx231xx_errdev("failed to set alternate setting !\n");
+
+ return ret;
+ }
+
+ /* inform hardware to start streaming */
+ ret = cx231xx_capture_start(dev, 1, Audio);
+
+ runtime->hw = snd_cx231xx_hw_capture;
+
+ mutex_lock(&dev->lock);
+ dev->adev.users++;
+ mutex_unlock(&dev->lock);
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ dev->adev.capture_pcm_substream = substream;
+ runtime->private_data = dev;
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static int snd_cx231xx_pcm_close(snd_pcm_substream_t *substream)
+#else
+static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
+#endif
+{
+ int ret;
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+ dprintk("closing device\n");
+
+ /* set alternate setting for audio interface */
+ /* 1 - 48000 samples per sec */
+ ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
+ if (ret < 0) {
+ cx231xx_errdev("failed to set alternate setting !\n");
+
+ return ret;
+ }
+
+ /* inform hardware to start streaming */
+ ret = cx231xx_capture_start(dev, 0, Audio);
+
+ dev->mute = 1;
+ mutex_lock(&dev->lock);
+ dev->adev.users--;
+ mutex_unlock(&dev->lock);
+
+ if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
+ dprintk("audio users: %d\n", dev->adev.users);
+ dprintk("disabling audio stream!\n");
+ dev->adev.shutdown = 0;
+ dprintk("released lock\n");
+ cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, 0);
+ }
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static int snd_cx231xx_hw_capture_params(snd_pcm_substream_t *substream,
+ snd_pcm_hw_params_t *hw_params)
+#else
+static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+#endif
+{
+ unsigned int channels, rate, format;
+ int ret;
+
+ dprintk("Setting capture parameters\n");
+
+ ret = snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+ format = params_format(hw_params);
+ rate = params_rate(hw_params);
+ channels = params_channels(hw_params);
+
+ /* TODO: set up cx231xx audio chip to deliver the correct audio format,
+ current default is 48000hz multiplexed => 96000hz mono
+ which shouldn't matter since analogue TV only supports mono */
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static int snd_cx231xx_hw_capture_free(snd_pcm_substream_t *substream)
+#else
+static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
+#endif
+{
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+ dprintk("Stop capture, if needed\n");
+
+ if (dev->adev.capture_stream == STREAM_ON)
+ cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static int snd_cx231xx_prepare(snd_pcm_substream_t *substream)
+#else
+static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
+#endif
+{
+ return 0;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static int snd_cx231xx_capture_trigger(snd_pcm_substream_t *substream, int cmd)
+#else
+static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+#endif
+{
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
+ int retval;
+
+ dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
+ "start" : "stop");
+
+ spin_lock(&dev->adev.slock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN,
+ CX231XX_START_AUDIO);
+ retval = 0;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
+ retval = 0;
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ spin_unlock(&dev->adev.slock);
+ return retval;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static snd_pcm_uframes_t snd_cx231xx_capture_pointer(snd_pcm_substream_t
+ *substream)
+#else
+static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
+ *substream)
+#endif
+{
+ struct cx231xx *dev;
+ unsigned long flags;
+ snd_pcm_uframes_t hwptr_done;
+
+ dev = snd_pcm_substream_chip(substream);
+
+ spin_lock_irqsave(&dev->adev.slock, flags);
+ hwptr_done = dev->adev.hwptr_done_capture;
+ spin_unlock_irqrestore(&dev->adev.slock, flags);
+
+ return hwptr_done;
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t * subs,
+ unsigned long offset)
+#else
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+#endif
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+static snd_pcm_ops_t snd_cx231xx_pcm_capture = {
+#else
+static struct snd_pcm_ops snd_cx231xx_pcm_capture = {
+#endif
+ .open = snd_cx231xx_capture_open,
+ .close = snd_cx231xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cx231xx_hw_capture_params,
+ .hw_free = snd_cx231xx_hw_capture_free,
+ .prepare = snd_cx231xx_prepare,
+ .trigger = snd_cx231xx_capture_trigger,
+ .pointer = snd_cx231xx_capture_pointer,
+ .page = snd_pcm_get_vmalloc_page,
+};
+
+static int cx231xx_audio_init(struct cx231xx *dev)
+{
+ struct cx231xx_audio *adev = &dev->adev;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ snd_pcm_t *pcm;
+ snd_card_t *card;
+#else
+ struct snd_pcm *pcm;
+ struct snd_card *card;
+#endif
+ static int devnr;
+ int err;
+ struct usb_interface *uif;
+ int i, isoc_pipe = 0;
+
+ if (dev->has_alsa_audio != 1) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module or
+ doesn't have analog audio support at all) */
+ return 0;
+ }
+
+ cx231xx_info("cx231xx-audio.c: probing for cx231xx "
+ "non standard usbaudio\n");
+
+ card = snd_card_new(index[devnr], "Cx231xx Audio", THIS_MODULE, 0);
+ if (card == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&adev->slock);
+ err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_cx231xx_pcm_capture);
+ pcm->info_flags = 0;
+ pcm->private_data = dev;
+ strcpy(pcm->name, "Conexant cx231xx Capture");
+ strcpy(card->driver, "Conexant cx231xx Audio");
+ strcpy(card->shortname, "Cx231xx Audio");
+ strcpy(card->longname, "Conexant cx231xx Audio");
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ adev->sndcard = card;
+ adev->udev = dev->udev;
+
+ /* compute alternate max packet sizes for Audio */
+ uif =
+ dev->udev->actconfig->interface[dev->current_pcb_config.
+ hs_config_info[0].interface_info.
+ audio_index + 1];
+
+ adev->end_point_addr =
+ le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress);
+
+ adev->num_alt = uif->num_altsetting;
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ adev->end_point_addr, adev->num_alt);
+ adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL);
+
+ if (adev->alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < adev->num_alt; i++) {
+ u16 tmp =
+ le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
+ wMaxPacketSize);
+ adev->alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ adev->alt_max_pkt_size[i]);
+ }
+
+ return 0;
+}
+
+static int cx231xx_audio_fini(struct cx231xx *dev)
+{
+ if (dev == NULL)
+ return 0;
+
+ if (dev->has_alsa_audio != 1) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module or
+ doesn't have analog audio support at all) */
+ return 0;
+ }
+
+ if (dev->adev.sndcard) {
+ snd_card_free(dev->adev.sndcard);
+ kfree(dev->adev.alt_max_pkt_size);
+ dev->adev.sndcard = NULL;
+ }
+
+ return 0;
+}
+
+static struct cx231xx_ops audio_ops = {
+ .id = CX231XX_AUDIO,
+ .name = "Cx231xx Audio Extension",
+ .init = cx231xx_audio_init,
+ .fini = cx231xx_audio_fini,
+};
+
+static int __init cx231xx_alsa_register(void)
+{
+ return cx231xx_register_extension(&audio_ops);
+}
+
+static void __exit cx231xx_alsa_unregister(void)
+{
+ cx231xx_unregister_extension(&audio_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
+MODULE_DESCRIPTION("Cx231xx Audio driver");
+
+module_init(cx231xx_alsa_register);
+module_exit(cx231xx_alsa_unregister);
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-avcore.c b/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
new file mode 100644
index 000000000..1be3881be
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -0,0 +1,2581 @@
+/*
+ cx231xx_avcore.c - driver for Conexant Cx23100/101/102
+ USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+ This program contains the specific code to control the avdecoder chip and
+ other related usb control functions for cx231xx based chipset.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "cx231xx.h"
+
+/******************************************************************************
+ -: BLOCK ARRANGEMENT :-
+ I2S block ----------------------|
+ [I2S audio] |
+ |
+ Analog Front End --> Direct IF -|-> Cx25840 --> Audio
+ [video & audio] | [Audio]
+ |
+ |-> Cx25840 --> Video
+ [Video]
+
+*******************************************************************************/
+
+/******************************************************************************
+ * A F E - B L O C K C O N T R O L functions *
+ * [ANALOG FRONT END] *
+ ******************************************************************************/
+static int afe_write_byte(struct cx231xx *dev, u16 saddr, u8 data)
+{
+ return cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ saddr, 2, data, 1);
+}
+
+static int afe_read_byte(struct cx231xx *dev, u16 saddr, u8 *data)
+{
+ int status;
+ u32 temp = 0;
+
+ status = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ saddr, 2, &temp, 1);
+ *data = (u8) temp;
+ return status;
+}
+
+int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count)
+{
+ int status = 0;
+ u8 temp = 0;
+ u8 afe_power_status = 0;
+ int i = 0;
+
+ /* super block initialize */
+ temp = (u8) (ref_count & 0xff);
+ status = afe_write_byte(dev, SUP_BLK_TUNE2, temp);
+ if (status < 0)
+ return status;
+
+ status = afe_read_byte(dev, SUP_BLK_TUNE2, &afe_power_status);
+ if (status < 0)
+ return status;
+
+ temp = (u8) ((ref_count & 0x300) >> 8);
+ temp |= 0x40;
+ status = afe_write_byte(dev, SUP_BLK_TUNE1, temp);
+ if (status < 0)
+ return status;
+
+ status = afe_write_byte(dev, SUP_BLK_PLL2, 0x0f);
+ if (status < 0)
+ return status;
+
+ /* enable pll */
+ while (afe_power_status != 0x18) {
+ status = afe_write_byte(dev, SUP_BLK_PWRDN, 0x18);
+ if (status < 0) {
+ cx231xx_info(
+ ": Init Super Block failed in send cmd\n");
+ break;
+ }
+
+ status = afe_read_byte(dev, SUP_BLK_PWRDN, &afe_power_status);
+ afe_power_status &= 0xff;
+ if (status < 0) {
+ cx231xx_info(
+ ": Init Super Block failed in receive cmd\n");
+ break;
+ }
+ i++;
+ if (i == 10) {
+ cx231xx_info(
+ ": Init Super Block force break in loop !!!!\n");
+ status = -1;
+ break;
+ }
+ }
+
+ if (status < 0)
+ return status;
+
+ /* start tuning filter */
+ status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x40);
+ if (status < 0)
+ return status;
+
+ msleep(5);
+
+ /* exit tuning */
+ status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x00);
+
+ return status;
+}
+
+int cx231xx_afe_init_channels(struct cx231xx *dev)
+{
+ int status = 0;
+
+ /* power up all 3 channels, clear pd_buffer */
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, 0x00);
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, 0x00);
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, 0x00);
+
+ /* Enable quantizer calibration */
+ status = afe_write_byte(dev, ADC_COM_QUANT, 0x02);
+
+ /* channel initialize, force modulator (fb) reset */
+ status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x17);
+ status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x17);
+ status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x17);
+
+ /* start quantilizer calibration */
+ status = afe_write_byte(dev, ADC_CAL_ATEST_CH1, 0x10);
+ status = afe_write_byte(dev, ADC_CAL_ATEST_CH2, 0x10);
+ status = afe_write_byte(dev, ADC_CAL_ATEST_CH3, 0x10);
+ msleep(5);
+
+ /* exit modulator (fb) reset */
+ status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x07);
+ status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x07);
+ status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x07);
+
+ /* enable the pre_clamp in each channel for single-ended input */
+ status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH1, 0xf0);
+ status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH2, 0xf0);
+ status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, 0xf0);
+
+ /* use diode instead of resistor, so set term_en to 0, res_en to 0 */
+ status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8,
+ ADC_QGAIN_RES_TRM_CH1, 3, 7, 0x00);
+ status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8,
+ ADC_QGAIN_RES_TRM_CH2, 3, 7, 0x00);
+ status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8,
+ ADC_QGAIN_RES_TRM_CH3, 3, 7, 0x00);
+
+ /* dynamic element matching off */
+ status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH1, 0x03);
+ status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH2, 0x03);
+ status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, 0x03);
+
+ return status;
+}
+
+int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev)
+{
+ u8 c_value = 0;
+ int status = 0;
+
+ status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH2, &c_value);
+ c_value &= (~(0x50));
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, c_value);
+
+ return status;
+}
+
+/*
+ The Analog Front End in Cx231xx has 3 channels. These
+ channels are used to share between different inputs
+ like tuner, s-video and composite inputs.
+
+ channel 1 ----- pin 1 to pin4(in reg is 1-4)
+ channel 2 ----- pin 5 to pin8(in reg is 5-8)
+ channel 3 ----- pin 9 to pin 12(in reg is 9-11)
+*/
+int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
+{
+ u8 ch1_setting = (u8) input_mux;
+ u8 ch2_setting = (u8) (input_mux >> 8);
+ u8 ch3_setting = (u8) (input_mux >> 16);
+ int status = 0;
+ u8 value = 0;
+
+ if (ch1_setting != 0) {
+ status = afe_read_byte(dev, ADC_INPUT_CH1, &value);
+ value &= (!INPUT_SEL_MASK);
+ value |= (ch1_setting - 1) << 4;
+ value &= 0xff;
+ status = afe_write_byte(dev, ADC_INPUT_CH1, value);
+ }
+
+ if (ch2_setting != 0) {
+ status = afe_read_byte(dev, ADC_INPUT_CH2, &value);
+ value &= (!INPUT_SEL_MASK);
+ value |= (ch2_setting - 1) << 4;
+ value &= 0xff;
+ status = afe_write_byte(dev, ADC_INPUT_CH2, value);
+ }
+
+ /* For ch3_setting, the value to put in the register is
+ 7 less than the input number */
+ if (ch3_setting != 0) {
+ status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
+ value &= (!INPUT_SEL_MASK);
+ value |= (ch3_setting - 1) << 4;
+ value &= 0xff;
+ status = afe_write_byte(dev, ADC_INPUT_CH3, value);
+ }
+
+ return status;
+}
+
+int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode)
+{
+ int status = 0;
+
+ /*
+ * FIXME: We need to implement the AFE code for LOW IF and for HI IF.
+ * Currently, only baseband works.
+ */
+
+ switch (mode) {
+ case AFE_MODE_LOW_IF:
+ /* SetupAFEforLowIF(); */
+ break;
+ case AFE_MODE_BASEBAND:
+ status = cx231xx_afe_setup_AFE_for_baseband(dev);
+ break;
+ case AFE_MODE_EU_HI_IF:
+ /* SetupAFEforEuHiIF(); */
+ break;
+ case AFE_MODE_US_HI_IF:
+ /* SetupAFEforUsHiIF(); */
+ break;
+ case AFE_MODE_JAPAN_HI_IF:
+ /* SetupAFEforJapanHiIF(); */
+ break;
+ }
+
+ if ((mode != dev->afe_mode) &&
+ (dev->video_input == CX231XX_VMUX_TELEVISION))
+ status = cx231xx_afe_adjust_ref_count(dev,
+ CX231XX_VMUX_TELEVISION);
+
+ dev->afe_mode = mode;
+
+ return status;
+}
+
+int cx231xx_afe_update_power_control(struct cx231xx *dev,
+ enum AV_MODE avmode)
+{
+ u8 afe_power_status = 0;
+ int status = 0;
+
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_RDU_250:
+ if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
+ while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL)) {
+ status = afe_write_byte(dev, SUP_BLK_PWRDN,
+ FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL);
+ status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+ &afe_power_status);
+ if (status < 0)
+ break;
+ }
+
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+ 0x00);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+ 0x00);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+ 0x00);
+ } else if (avmode == POLARIS_AVMODE_DIGITAL) {
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+ 0x70);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+ 0x70);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+ 0x70);
+
+ status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+ &afe_power_status);
+ afe_power_status |= FLD_PWRDN_PD_BANDGAP |
+ FLD_PWRDN_PD_BIAS |
+ FLD_PWRDN_PD_TUNECK;
+ status |= afe_write_byte(dev, SUP_BLK_PWRDN,
+ afe_power_status);
+ } else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) {
+ while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL)) {
+ status = afe_write_byte(dev, SUP_BLK_PWRDN,
+ FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL);
+ status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+ &afe_power_status);
+ if (status < 0)
+ break;
+ }
+
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+ 0x00);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+ 0x00);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+ 0x00);
+ } else {
+ cx231xx_info("Invalid AV mode input\n");
+ status = -1;
+ }
+ break;
+ default:
+ if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
+ while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL)) {
+ status = afe_write_byte(dev, SUP_BLK_PWRDN,
+ FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL);
+ status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+ &afe_power_status);
+ if (status < 0)
+ break;
+ }
+
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+ 0x40);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+ 0x40);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+ 0x00);
+ } else if (avmode == POLARIS_AVMODE_DIGITAL) {
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+ 0x70);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+ 0x70);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+ 0x70);
+
+ status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+ &afe_power_status);
+ afe_power_status |= FLD_PWRDN_PD_BANDGAP |
+ FLD_PWRDN_PD_BIAS |
+ FLD_PWRDN_PD_TUNECK;
+ status |= afe_write_byte(dev, SUP_BLK_PWRDN,
+ afe_power_status);
+ } else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) {
+ while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL)) {
+ status = afe_write_byte(dev, SUP_BLK_PWRDN,
+ FLD_PWRDN_TUNING_BIAS |
+ FLD_PWRDN_ENABLE_PLL);
+ status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+ &afe_power_status);
+ if (status < 0)
+ break;
+ }
+
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+ 0x00);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+ 0x00);
+ status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+ 0x40);
+ } else {
+ cx231xx_info("Invalid AV mode input\n");
+ status = -1;
+ }
+ } /* switch */
+
+ return status;
+}
+
+int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input)
+{
+ u8 input_mode = 0;
+ u8 ntf_mode = 0;
+ int status = 0;
+
+ dev->video_input = video_input;
+
+ if (video_input == CX231XX_VMUX_TELEVISION) {
+ status = afe_read_byte(dev, ADC_INPUT_CH3, &input_mode);
+ status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3,
+ &ntf_mode);
+ } else {
+ status = afe_read_byte(dev, ADC_INPUT_CH1, &input_mode);
+ status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH1,
+ &ntf_mode);
+ }
+
+ input_mode = (ntf_mode & 0x3) | ((input_mode & 0x6) << 1);
+
+ switch (input_mode) {
+ case SINGLE_ENDED:
+ dev->afe_ref_count = 0x23C;
+ break;
+ case LOW_IF:
+ dev->afe_ref_count = 0x24C;
+ break;
+ case EU_IF:
+ dev->afe_ref_count = 0x258;
+ break;
+ case US_IF:
+ dev->afe_ref_count = 0x260;
+ break;
+ default:
+ break;
+ }
+
+ status = cx231xx_afe_init_super_block(dev, dev->afe_ref_count);
+
+ return status;
+}
+
+/******************************************************************************
+ * V I D E O / A U D I O D E C O D E R C O N T R O L functions *
+ ******************************************************************************/
+static int vid_blk_write_byte(struct cx231xx *dev, u16 saddr, u8 data)
+{
+ return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ saddr, 2, data, 1);
+}
+
+static int vid_blk_read_byte(struct cx231xx *dev, u16 saddr, u8 *data)
+{
+ int status;
+ u32 temp = 0;
+
+ status = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ saddr, 2, &temp, 1);
+ *data = (u8) temp;
+ return status;
+}
+
+static int vid_blk_write_word(struct cx231xx *dev, u16 saddr, u32 data)
+{
+ return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ saddr, 2, data, 4);
+}
+
+static int vid_blk_read_word(struct cx231xx *dev, u16 saddr, u32 *data)
+{
+ return cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ saddr, 2, data, 4);
+}
+
+int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
+{
+ int status = 0;
+
+ switch (INPUT(input)->type) {
+ case CX231XX_VMUX_COMPOSITE1:
+ case CX231XX_VMUX_SVIDEO:
+ if ((dev->current_pcb_config.type == USB_BUS_POWER) &&
+ (dev->power_mode != POLARIS_AVMODE_ENXTERNAL_AV)) {
+ /* External AV */
+ status = cx231xx_set_power_mode(dev,
+ POLARIS_AVMODE_ENXTERNAL_AV);
+ if (status < 0) {
+ cx231xx_errdev("%s: set_power_mode : Failed to"
+ " set Power - errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+ }
+ status = cx231xx_set_decoder_video_input(dev,
+ INPUT(input)->type,
+ INPUT(input)->vmux);
+ break;
+ case CX231XX_VMUX_TELEVISION:
+ case CX231XX_VMUX_CABLE:
+ if ((dev->current_pcb_config.type == USB_BUS_POWER) &&
+ (dev->power_mode != POLARIS_AVMODE_ANALOGT_TV)) {
+ /* Tuner */
+ status = cx231xx_set_power_mode(dev,
+ POLARIS_AVMODE_ANALOGT_TV);
+ if (status < 0) {
+ cx231xx_errdev("%s: set_power_mode:Failed"
+ " to set Power - errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+ }
+ status = cx231xx_set_decoder_video_input(dev,
+ CX231XX_VMUX_COMPOSITE1,
+ INPUT(input)->vmux);
+ break;
+ default:
+ cx231xx_errdev("%s: set_power_mode : Unknown Input %d !\n",
+ __func__, INPUT(input)->type);
+ break;
+ }
+
+ /* save the selection */
+ dev->video_input = input;
+
+ return status;
+}
+
+int cx231xx_set_decoder_video_input(struct cx231xx *dev,
+ u8 pin_type, u8 input)
+{
+ int status = 0;
+ u32 value = 0;
+
+ if (pin_type != dev->video_input) {
+ status = cx231xx_afe_adjust_ref_count(dev, pin_type);
+ if (status < 0) {
+ cx231xx_errdev("%s: adjust_ref_count :Failed to set"
+ "AFE input mux - errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+ }
+
+ /* call afe block to set video inputs */
+ status = cx231xx_afe_set_input_mux(dev, input);
+ if (status < 0) {
+ cx231xx_errdev("%s: set_input_mux :Failed to set"
+ " AFE input mux - errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+
+ switch (pin_type) {
+ case CX231XX_VMUX_COMPOSITE1:
+ status = vid_blk_read_word(dev, AFE_CTRL, &value);
+ value |= (0 << 13) | (1 << 4);
+ value &= ~(1 << 5);
+
+ /* set [24:23] [22:15] to 0 */
+ value &= (~(0x1ff8000));
+ /* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0 */
+ value |= 0x1000000;
+ status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+ status = vid_blk_read_word(dev, OUT_CTRL1, &value);
+ value |= (1 << 7);
+ status = vid_blk_write_word(dev, OUT_CTRL1, value);
+
+ /* Set vip 1.1 output mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ OUT_CTRL1,
+ FLD_OUT_MODE,
+ OUT_MODE_VIP11);
+
+ /* Tell DIF object to go to baseband mode */
+ status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
+ if (status < 0) {
+ cx231xx_errdev("%s: cx231xx_dif set to By pass"
+ " mode- errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+
+ /* Read the DFE_CTRL1 register */
+ status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+ /* enable the VBI_GATE_EN */
+ value |= FLD_VBI_GATE_EN;
+
+ /* Enable the auto-VGA enable */
+ value |= FLD_VGA_AUTO_EN;
+
+ /* Write it back */
+ status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+ /* Disable auto config of registers */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL, FLD_ACFG_DIS,
+ cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+ /* Set CVBS input mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL, FLD_INPUT_MODE,
+ cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_CVBS_0));
+ break;
+ case CX231XX_VMUX_SVIDEO:
+ /* Disable the use of DIF */
+
+ status = vid_blk_read_word(dev, AFE_CTRL, &value);
+
+ /* set [24:23] [22:15] to 0 */
+ value &= (~(0x1ff8000));
+ /* set FUNC_MODE[24:23] = 2
+ IF_MOD[22:15] = 0 DCR_BYP_CH2[4:4] = 1; */
+ value |= 0x1000010;
+ status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+ /* Tell DIF object to go to baseband mode */
+ status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
+ if (status < 0) {
+ cx231xx_errdev("%s: cx231xx_dif set to By pass"
+ " mode- errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+
+ /* Read the DFE_CTRL1 register */
+ status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+ /* enable the VBI_GATE_EN */
+ value |= FLD_VBI_GATE_EN;
+
+ /* Enable the auto-VGA enable */
+ value |= FLD_VGA_AUTO_EN;
+
+ /* Write it back */
+ status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+ /* Disable auto config of registers */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL, FLD_ACFG_DIS,
+ cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+ /* Set YC input mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL,
+ FLD_INPUT_MODE,
+ cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_YC_1));
+
+ /* Chroma to ADC2 */
+ status = vid_blk_read_word(dev, AFE_CTRL, &value);
+ value |= FLD_CHROMA_IN_SEL; /* set the chroma in select */
+
+ /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8)
+ This sets them to use video
+ rather than audio. Only one of the two will be in use. */
+ value &= ~(FLD_VGA_SEL_CH2 | FLD_VGA_SEL_CH3);
+
+ status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+ status = cx231xx_afe_set_mode(dev, AFE_MODE_BASEBAND);
+ break;
+ case CX231XX_VMUX_TELEVISION:
+ case CX231XX_VMUX_CABLE:
+ default:
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_RDU_250:
+ /* Disable the use of DIF */
+
+ status = vid_blk_read_word(dev, AFE_CTRL, &value);
+ value |= (0 << 13) | (1 << 4);
+ value &= ~(1 << 5);
+
+ /* set [24:23] [22:15] to 0 */
+ value &= (~(0x1FF8000));
+ /* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0 */
+ value |= 0x1000000;
+ status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+ status = vid_blk_read_word(dev, OUT_CTRL1, &value);
+ value |= (1 << 7);
+ status = vid_blk_write_word(dev, OUT_CTRL1, value);
+
+ /* Set vip 1.1 output mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ OUT_CTRL1, FLD_OUT_MODE,
+ OUT_MODE_VIP11);
+
+ /* Tell DIF object to go to baseband mode */
+ status = cx231xx_dif_set_standard(dev,
+ DIF_USE_BASEBAND);
+ if (status < 0) {
+ cx231xx_errdev("%s: cx231xx_dif set to By pass"
+ " mode- errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+
+ /* Read the DFE_CTRL1 register */
+ status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+ /* enable the VBI_GATE_EN */
+ value |= FLD_VBI_GATE_EN;
+
+ /* Enable the auto-VGA enable */
+ value |= FLD_VGA_AUTO_EN;
+
+ /* Write it back */
+ status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+ /* Disable auto config of registers */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL, FLD_ACFG_DIS,
+ cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+ /* Set CVBS input mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL, FLD_INPUT_MODE,
+ cx231xx_set_field(FLD_INPUT_MODE,
+ INPUT_MODE_CVBS_0));
+ break;
+ default:
+ /* Enable the DIF for the tuner */
+
+ /* Reinitialize the DIF */
+ status = cx231xx_dif_set_standard(dev, dev->norm);
+ if (status < 0) {
+ cx231xx_errdev("%s: cx231xx_dif set to By pass"
+ " mode- errCode [%d]!\n",
+ __func__, status);
+ return status;
+ }
+
+ /* Make sure bypass is cleared */
+ status = vid_blk_read_word(dev, DIF_MISC_CTRL, &value);
+
+ /* Clear the bypass bit */
+ value &= ~FLD_DIF_DIF_BYPASS;
+
+ /* Enable the use of the DIF block */
+ status = vid_blk_write_word(dev, DIF_MISC_CTRL, value);
+
+ /* Read the DFE_CTRL1 register */
+ status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+ /* Disable the VBI_GATE_EN */
+ value &= ~FLD_VBI_GATE_EN;
+
+ /* Enable the auto-VGA enable, AGC, and
+ set the skip count to 2 */
+ value |= FLD_VGA_AUTO_EN | FLD_AGC_AUTO_EN | 0x00200000;
+
+ /* Write it back */
+ status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+ /* Wait until AGC locks up */
+ msleep(1);
+
+ /* Disable the auto-VGA enable AGC */
+ value &= ~(FLD_VGA_AUTO_EN);
+
+ /* Write it back */
+ status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+ /* Enable Polaris B0 AGC output */
+ status = vid_blk_read_word(dev, PIN_CTRL, &value);
+ value |= (FLD_OEF_AGC_RF) |
+ (FLD_OEF_AGC_IFVGA) |
+ (FLD_OEF_AGC_IF);
+ status = vid_blk_write_word(dev, PIN_CTRL, value);
+
+ /* Set vip 1.1 output mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ OUT_CTRL1, FLD_OUT_MODE,
+ OUT_MODE_VIP11);
+
+ /* Disable auto config of registers */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL, FLD_ACFG_DIS,
+ cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+ /* Set CVBS input mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ MODE_CTRL, FLD_INPUT_MODE,
+ cx231xx_set_field(FLD_INPUT_MODE,
+ INPUT_MODE_CVBS_0));
+
+ /* Set some bits in AFE_CTRL so that channel 2 or 3
+ * is ready to receive audio */
+ /* Clear clamp for channels 2 and 3 (bit 16-17) */
+ /* Clear droop comp (bit 19-20) */
+ /* Set VGA_SEL (for audio control) (bit 7-8) */
+ status = vid_blk_read_word(dev, AFE_CTRL, &value);
+
+ value |= FLD_VGA_SEL_CH3 | FLD_VGA_SEL_CH2;
+
+ status = vid_blk_write_word(dev, AFE_CTRL, value);
+ break;
+
+ }
+ break;
+ }
+
+ /* Set raw VBI mode */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ OUT_CTRL1, FLD_VBIHACTRAW_EN,
+ cx231xx_set_field(FLD_VBIHACTRAW_EN, 1));
+
+ status = vid_blk_read_word(dev, OUT_CTRL1, &value);
+ if (value & 0x02) {
+ value |= (1 << 19);
+ status = vid_blk_write_word(dev, OUT_CTRL1, value);
+ }
+
+ return status;
+}
+
+/*
+ * Handle any video-mode specific overrides that are different
+ * on a per video standards basis after touching the MODE_CTRL
+ * register which resets many values for autodetect
+ */
+int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
+{
+ int status = 0;
+
+ cx231xx_info("do_mode_ctrl_overrides : 0x%x\n",
+ (unsigned int)dev->norm);
+
+ /* Change the DFE_CTRL3 bp_percent to fix flagging */
+ status = vid_blk_write_word(dev, DFE_CTRL3, 0xCD3F0280);
+
+ if (dev->norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) {
+ cx231xx_info("do_mode_ctrl_overrides NTSC\n");
+
+ /* Move the close caption lines out of active video,
+ adjust the active video start point */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_VBLANK_CNT, 0x18);
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_VACTIVE_CNT,
+ 0x1E6000);
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_V656BLANK_CNT,
+ 0x1E000000);
+
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ HORIZ_TIM_CTRL,
+ FLD_HBLANK_CNT,
+ cx231xx_set_field
+ (FLD_HBLANK_CNT, 0x79));
+ } else if (dev->norm & V4L2_STD_SECAM) {
+ cx231xx_info("do_mode_ctrl_overrides SECAM\n");
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_VBLANK_CNT, 0x24);
+ /* Adjust the active video horizontal start point */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ HORIZ_TIM_CTRL,
+ FLD_HBLANK_CNT,
+ cx231xx_set_field
+ (FLD_HBLANK_CNT, 0x85));
+ } else {
+ cx231xx_info("do_mode_ctrl_overrides PAL\n");
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_VBLANK_CNT, 0x24);
+ /* Adjust the active video horizontal start point */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ HORIZ_TIM_CTRL,
+ FLD_HBLANK_CNT,
+ cx231xx_set_field
+ (FLD_HBLANK_CNT, 0x85));
+ }
+
+ return status;
+}
+
+int cx231xx_set_audio_input(struct cx231xx *dev, u8 input)
+{
+ int status = 0;
+ enum AUDIO_INPUT ainput = AUDIO_INPUT_LINE;
+
+ switch (INPUT(input)->amux) {
+ case CX231XX_AMUX_VIDEO:
+ ainput = AUDIO_INPUT_TUNER_TV;
+ break;
+ case CX231XX_AMUX_LINE_IN:
+ status = cx231xx_i2s_blk_set_audio_input(dev, input);
+ ainput = AUDIO_INPUT_LINE;
+ break;
+ default:
+ break;
+ }
+
+ status = cx231xx_set_audio_decoder_input(dev, ainput);
+
+ return status;
+}
+
+int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
+ enum AUDIO_INPUT audio_input)
+{
+ u32 dwval;
+ int status;
+ u8 gen_ctrl;
+ u32 value = 0;
+
+ /* Put it in soft reset */
+ status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl);
+ gen_ctrl |= 1;
+ status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl);
+
+ switch (audio_input) {
+ case AUDIO_INPUT_LINE:
+ /* setup AUD_IO control from Merlin paralle output */
+ value = cx231xx_set_field(FLD_AUD_CHAN1_SRC,
+ AUD_CHAN_SRC_PARALLEL);
+ status = vid_blk_write_word(dev, AUD_IO_CTRL, value);
+
+ /* setup input to Merlin, SRC2 connect to AC97
+ bypass upsample-by-2, slave mode, sony mode, left justify
+ adr 091c, dat 01000000 */
+ status = vid_blk_read_word(dev, AC97_CTL, &dwval);
+
+ status = vid_blk_write_word(dev, AC97_CTL,
+ (dwval | FLD_AC97_UP2X_BYPASS));
+
+ /* select the parallel1 and SRC3 */
+ status = vid_blk_write_word(dev, BAND_OUT_SEL,
+ cx231xx_set_field(FLD_SRC3_IN_SEL, 0x0) |
+ cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x0) |
+ cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x0));
+
+ /* unmute all, AC97 in, independence mode
+ adr 08d0, data 0x00063073 */
+ status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063073);
+
+ /* set AVC maximum threshold, adr 08d4, dat ffff0024 */
+ status = vid_blk_read_word(dev, PATH1_VOL_CTL, &dwval);
+ status = vid_blk_write_word(dev, PATH1_VOL_CTL,
+ (dwval | FLD_PATH1_AVC_THRESHOLD));
+
+ /* set SC maximum threshold, adr 08ec, dat ffffb3a3 */
+ status = vid_blk_read_word(dev, PATH1_SC_CTL, &dwval);
+ status = vid_blk_write_word(dev, PATH1_SC_CTL,
+ (dwval | FLD_PATH1_SC_THRESHOLD));
+ break;
+
+ case AUDIO_INPUT_TUNER_TV:
+ default:
+
+ /* Setup SRC sources and clocks */
+ status = vid_blk_write_word(dev, BAND_OUT_SEL,
+ cx231xx_set_field(FLD_SRC6_IN_SEL, 0x00) |
+ cx231xx_set_field(FLD_SRC6_CLK_SEL, 0x01) |
+ cx231xx_set_field(FLD_SRC5_IN_SEL, 0x00) |
+ cx231xx_set_field(FLD_SRC5_CLK_SEL, 0x02) |
+ cx231xx_set_field(FLD_SRC4_IN_SEL, 0x02) |
+ cx231xx_set_field(FLD_SRC4_CLK_SEL, 0x03) |
+ cx231xx_set_field(FLD_SRC3_IN_SEL, 0x00) |
+ cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x00) |
+ cx231xx_set_field(FLD_BASEBAND_BYPASS_CTL, 0x00) |
+ cx231xx_set_field(FLD_AC97_SRC_SEL, 0x03) |
+ cx231xx_set_field(FLD_I2S_SRC_SEL, 0x00) |
+ cx231xx_set_field(FLD_PARALLEL2_SRC_SEL, 0x02) |
+ cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x01));
+
+ /* Setup the AUD_IO control */
+ status = vid_blk_write_word(dev, AUD_IO_CTRL,
+ cx231xx_set_field(FLD_I2S_PORT_DIR, 0x00) |
+ cx231xx_set_field(FLD_I2S_OUT_SRC, 0x00) |
+ cx231xx_set_field(FLD_AUD_CHAN3_SRC, 0x00) |
+ cx231xx_set_field(FLD_AUD_CHAN2_SRC, 0x00) |
+ cx231xx_set_field(FLD_AUD_CHAN1_SRC, 0x03));
+
+ status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F063870);
+
+ /* setAudioStandard(_audio_standard); */
+
+ status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063870);
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_RDU_250:
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ CHIP_CTRL,
+ FLD_SIF_EN,
+ cx231xx_set_field(FLD_SIF_EN, 1));
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case AUDIO_INPUT_TUNER_FM:
+ /* use SIF for FM radio
+ setupFM();
+ setAudioStandard(_audio_standard);
+ */
+ break;
+
+ case AUDIO_INPUT_MUTE:
+ status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F011012);
+ break;
+ }
+
+ /* Take it out of soft reset */
+ status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl);
+ gen_ctrl &= ~1;
+ status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl);
+
+ return status;
+}
+
+/* Set resolution of the video */
+int cx231xx_resolution_set(struct cx231xx *dev)
+{
+ int width, height;
+ u32 hscale, vscale;
+ int status = 0;
+
+ width = dev->width;
+ height = dev->height;
+
+ get_scale(dev, width, height, &hscale, &vscale);
+
+ /* set horzontal scale */
+ status = vid_blk_write_word(dev, HSCALE_CTRL, hscale);
+
+ /* set vertical scale */
+ status = vid_blk_write_word(dev, VSCALE_CTRL, vscale);
+
+ return status;
+}
+
+/******************************************************************************
+ * C H I P Specific C O N T R O L functions *
+ ******************************************************************************/
+int cx231xx_init_ctrl_pin_status(struct cx231xx *dev)
+{
+ u32 value;
+ int status = 0;
+
+ status = vid_blk_read_word(dev, PIN_CTRL, &value);
+ value |= (~dev->board.ctl_pin_status_mask);
+ status = vid_blk_write_word(dev, PIN_CTRL, value);
+
+ return status;
+}
+
+int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
+ u8 analog_or_digital)
+{
+ int status = 0;
+
+ /* first set the direction to output */
+ status = cx231xx_set_gpio_direction(dev,
+ dev->board.
+ agc_analog_digital_select_gpio, 1);
+
+ /* 0 - demod ; 1 - Analog mode */
+ status = cx231xx_set_gpio_value(dev,
+ dev->board.agc_analog_digital_select_gpio,
+ analog_or_digital);
+
+ return status;
+}
+
+int cx231xx_enable_i2c_for_tuner(struct cx231xx *dev, u8 I2CIndex)
+{
+ u8 value[4] = { 0, 0, 0, 0 };
+ int status = 0;
+
+ cx231xx_info("Changing the i2c port for tuner to %d\n", I2CIndex);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ if (status < 0)
+ return status;
+
+ if (I2CIndex == I2C_1) {
+ if (value[0] & I2C_DEMOD_EN) {
+ value[0] &= ~I2C_DEMOD_EN;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ }
+ } else {
+ if (!(value[0] & I2C_DEMOD_EN)) {
+ value[0] |= I2C_DEMOD_EN;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ }
+ }
+
+ return status;
+
+}
+
+/******************************************************************************
+ * D I F - B L O C K C O N T R O L functions *
+ ******************************************************************************/
+int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
+ u32 function_mode, u32 standard)
+{
+ int status = 0;
+
+ if (mode == V4L2_TUNER_RADIO) {
+ /* C2HH */
+ /* lo if big signal */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+ /* FUNC_MODE = DIF */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 23, 24, function_mode);
+ /* IF_MODE */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xFF);
+ /* no inv */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+ } else if (standard != DIF_USE_BASEBAND) {
+ if (standard & V4L2_STD_MN) {
+ /* lo if big signal */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+ /* FUNC_MODE = DIF */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 23, 24,
+ function_mode);
+ /* IF_MODE */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xb);
+ /* no inv */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+ /* 0x124, AUD_CHAN1_SRC = 0x3 */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AUD_IO_CTRL, 0, 31, 0x00000003);
+ } else if ((standard == V4L2_STD_PAL_I) |
+ (standard & V4L2_STD_SECAM)) {
+ /* C2HH setup */
+ /* lo if big signal */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+ /* FUNC_MODE = DIF */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 23, 24,
+ function_mode);
+ /* IF_MODE */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xF);
+ /* no inv */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+ } else {
+ /* default PAL BG */
+ /* C2HH setup */
+ /* lo if big signal */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+ /* FUNC_MODE = DIF */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 23, 24,
+ function_mode);
+ /* IF_MODE */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xE);
+ /* no inv */
+ status = cx231xx_reg_mask_write(dev,
+ VID_BLK_I2C_ADDRESS, 32,
+ AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+ }
+ }
+
+ return status;
+}
+
+int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
+{
+ int status = 0;
+ u32 dif_misc_ctrl_value = 0;
+ u32 func_mode = 0;
+
+ cx231xx_info("%s: setStandard to %x\n", __func__, standard);
+
+ status = vid_blk_read_word(dev, DIF_MISC_CTRL, &dif_misc_ctrl_value);
+ if (standard != DIF_USE_BASEBAND)
+ dev->norm = standard;
+
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_RDU_250:
+ func_mode = 0x03;
+ break;
+ default:
+ func_mode = 0x01;
+ }
+
+ status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
+ func_mode, standard);
+
+ if (standard == DIF_USE_BASEBAND) { /* base band */
+ /* There is a different SRC_PHASE_INC value
+ for baseband vs. DIF */
+ status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0xDF7DF83);
+ status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+ &dif_misc_ctrl_value);
+ dif_misc_ctrl_value |= FLD_DIF_DIF_BYPASS;
+ status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+ dif_misc_ctrl_value);
+ } else if (standard & V4L2_STD_PAL_D) {
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL3, 0, 31, 0x00008800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_REF, 0, 31, 0x444C1380);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_IF, 0, 31, 0xDA302600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_INT, 0, 31, 0xDA261700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_RF, 0, 31, 0xDA262600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_INT_CURRENT, 0, 31,
+ 0x26001700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_RF_CURRENT, 0, 31,
+ 0x00002660);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VIDEO_AGC_CTRL, 0, 31,
+ 0x72500800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VID_AUD_OVERRIDE, 0, 31,
+ 0x27000100);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AV_SEP_CTRL, 0, 31, 0x3F3934EA);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_COMP_FLT_CTRL, 0, 31,
+ 0x00000000);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_PHASE_INC, 0, 31,
+ 0x1befbf06);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_GAIN_CONTROL, 0, 31,
+ 0x000035e8);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value |= 0x3a023F11;
+ } else if (standard & V4L2_STD_PAL_I) {
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL3, 0, 31, 0x00008800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_REF, 0, 31, 0x444C1380);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_IF, 0, 31, 0xDA302600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_INT, 0, 31, 0xDA261700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_RF, 0, 31, 0xDA262600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_INT_CURRENT, 0, 31,
+ 0x26001700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_RF_CURRENT, 0, 31,
+ 0x00002660);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VIDEO_AGC_CTRL, 0, 31,
+ 0x72500800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VID_AUD_OVERRIDE, 0, 31,
+ 0x27000100);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AV_SEP_CTRL, 0, 31, 0x5F39A934);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_COMP_FLT_CTRL, 0, 31,
+ 0x00000000);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_PHASE_INC, 0, 31,
+ 0x1befbf06);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_GAIN_CONTROL, 0, 31,
+ 0x000035e8);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value |= 0x3a033F11;
+ } else if (standard & V4L2_STD_PAL_M) {
+ /* improved Low Frequency Phase Noise */
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800);
+ status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380);
+ status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT,
+ 0x26001700);
+ status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT,
+ 0x00002660);
+ status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL,
+ 0x72500800);
+ status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE,
+ 0x27000100);
+ status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x012c405d);
+ status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL,
+ 0x009f50c1);
+ status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC,
+ 0x1befbf06);
+ status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL,
+ 0x000035e8);
+ status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB,
+ 0x00000000);
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value |= 0x3A0A3F10;
+ } else if (standard & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
+ /* improved Low Frequency Phase Noise */
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800);
+ status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380);
+ status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT,
+ 0x26001700);
+ status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT,
+ 0x00002660);
+ status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL,
+ 0x72500800);
+ status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE,
+ 0x27000100);
+ status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL,
+ 0x012c405d);
+ status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL,
+ 0x009f50c1);
+ status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC,
+ 0x1befbf06);
+ status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL,
+ 0x000035e8);
+ status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB,
+ 0x00000000);
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value = 0x3A093F10;
+ } else if (standard &
+ (V4L2_STD_SECAM_B | V4L2_STD_SECAM_D | V4L2_STD_SECAM_G |
+ V4L2_STD_SECAM_K | V4L2_STD_SECAM_K1)) {
+
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL3, 0, 31, 0x00008800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_REF, 0, 31, 0x888C0380);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_IF, 0, 31, 0xe0262600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_INT, 0, 31, 0xc2171700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_RF, 0, 31, 0xc2262600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_INT_CURRENT, 0, 31,
+ 0x26001700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_RF_CURRENT, 0, 31,
+ 0x00002660);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VID_AUD_OVERRIDE, 0, 31,
+ 0x27000100);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_COMP_FLT_CTRL, 0, 31,
+ 0x00000000);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_PHASE_INC, 0, 31,
+ 0x1befbf06);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_GAIN_CONTROL, 0, 31,
+ 0x000035e8);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VIDEO_AGC_CTRL, 0, 31,
+ 0xf4000000);
+
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value |= 0x3a023F11;
+ } else if (standard & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) {
+ /* Is it SECAM_L1? */
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL3, 0, 31, 0x00008800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_REF, 0, 31, 0x888C0380);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_IF, 0, 31, 0xe0262600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_INT, 0, 31, 0xc2171700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_RF, 0, 31, 0xc2262600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_INT_CURRENT, 0, 31,
+ 0x26001700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_RF_CURRENT, 0, 31,
+ 0x00002660);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VID_AUD_OVERRIDE, 0, 31,
+ 0x27000100);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_COMP_FLT_CTRL, 0, 31,
+ 0x00000000);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_PHASE_INC, 0, 31,
+ 0x1befbf06);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_GAIN_CONTROL, 0, 31,
+ 0x000035e8);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VIDEO_AGC_CTRL, 0, 31,
+ 0xf2560000);
+
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value |= 0x3a023F11;
+
+ } else if (standard & V4L2_STD_NTSC_M) {
+ /* V4L2_STD_NTSC_M (75 IRE Setup) Or
+ V4L2_STD_NTSC_M_JP (Japan, 0 IRE Setup) */
+
+ /* For NTSC the centre frequency of video coming out of
+ sidewinder is around 7.1MHz or 3.6MHz depending on the
+ spectral inversion. so for a non spectrally inverted channel
+ the pll freq word is 0x03420c49
+ */
+
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0x6503BC0C);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xBD038C85);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1DB4640A);
+ status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800);
+ status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C0380);
+ status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT,
+ 0x26001700);
+ status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT,
+ 0x00002660);
+ status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL,
+ 0x04000800);
+ status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE,
+ 0x27000100);
+ status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x01296e1f);
+
+ status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL,
+ 0x009f50c1);
+ status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC,
+ 0x1befbf06);
+ status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL,
+ 0x000035e8);
+
+ status = vid_blk_write_word(dev, DIF_AGC_CTRL_IF, 0xC2262600);
+ status = vid_blk_write_word(dev, DIF_AGC_CTRL_INT,
+ 0xC2262600);
+ status = vid_blk_write_word(dev, DIF_AGC_CTRL_RF, 0xC2262600);
+
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value |= 0x3a003F10;
+ } else {
+ /* default PAL BG */
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_PLL_CTRL3, 0, 31, 0x00008800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_REF, 0, 31, 0x444C1380);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_IF, 0, 31, 0xDA302600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_INT, 0, 31, 0xDA261700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_CTRL_RF, 0, 31, 0xDA262600);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_IF_INT_CURRENT, 0, 31,
+ 0x26001700);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AGC_RF_CURRENT, 0, 31,
+ 0x00002660);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VIDEO_AGC_CTRL, 0, 31,
+ 0x72500800);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_VID_AUD_OVERRIDE, 0, 31,
+ 0x27000100);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_AV_SEP_CTRL, 0, 31, 0x3F3530EC);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_COMP_FLT_CTRL, 0, 31,
+ 0x00A653A8);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_PHASE_INC, 0, 31,
+ 0x1befbf06);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_SRC_GAIN_CONTROL, 0, 31,
+ 0x000035e8);
+ status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+ DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+ /* Save the Spec Inversion value */
+ dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+ dif_misc_ctrl_value |= 0x3a013F11;
+ }
+
+ /* The AGC values should be the same for all standards,
+ AUD_SRC_SEL[19] should always be disabled */
+ dif_misc_ctrl_value &= ~FLD_DIF_AUD_SRC_SEL;
+
+ /* It is still possible to get Set Standard calls even when we
+ are in FM mode.
+ This is done to override the value for FM. */
+ if (dev->active_mode == V4L2_TUNER_RADIO)
+ dif_misc_ctrl_value = 0x7a080000;
+
+ /* Write the calculated value for misc ontrol register */
+ status = vid_blk_write_word(dev, DIF_MISC_CTRL, dif_misc_ctrl_value);
+
+ return status;
+}
+
+int cx231xx_tuner_pre_channel_change(struct cx231xx *dev)
+{
+ int status = 0;
+ u32 dwval;
+
+ /* Set the RF and IF k_agc values to 3 */
+ status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval);
+ dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF);
+ dwval |= 0x33000000;
+
+ status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
+
+ return status;
+}
+
+int cx231xx_tuner_post_channel_change(struct cx231xx *dev)
+{
+ int status = 0;
+ u32 dwval;
+
+ /* Set the RF and IF k_agc values to 4 for PAL/NTSC and 8 for
+ * SECAM L/B/D standards */
+ status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval);
+ dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF);
+
+ if (dev->norm & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_B |
+ V4L2_STD_SECAM_D))
+ dwval |= 0x88000000;
+ else
+ dwval |= 0x44000000;
+
+ status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
+
+ return status;
+}
+
+/******************************************************************************
+ * I 2 S - B L O C K C O N T R O L functions *
+ ******************************************************************************/
+int cx231xx_i2s_blk_initialize(struct cx231xx *dev)
+{
+ int status = 0;
+ u32 value;
+
+ status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL1, 1, &value, 1);
+ /* enables clock to delta-sigma and decimation filter */
+ value |= 0x80;
+ status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL1, 1, value, 1);
+ /* power up all channel */
+ status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL2, 1, 0x00, 1);
+
+ return status;
+}
+
+int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev,
+ enum AV_MODE avmode)
+{
+ int status = 0;
+ u32 value = 0;
+
+ if (avmode != POLARIS_AVMODE_ENXTERNAL_AV) {
+ status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL2, 1, &value, 1);
+ value |= 0xfe;
+ status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL2, 1, value, 1);
+ } else {
+ status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL2, 1, 0x00, 1);
+ }
+
+ return status;
+}
+
+/* set i2s_blk for audio input types */
+int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input)
+{
+ int status = 0;
+
+ switch (audio_input) {
+ case CX231XX_AMUX_LINE_IN:
+ status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL2, 1, 0x00, 1);
+ status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ CH_PWR_CTRL1, 1, 0x80, 1);
+ break;
+ case CX231XX_AMUX_VIDEO:
+ default:
+ break;
+ }
+
+ dev->ctl_ainput = audio_input;
+
+ return status;
+}
+
+/******************************************************************************
+ * P O W E R C O N T R O L functions *
+ ******************************************************************************/
+int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
+{
+ u8 value[4] = { 0, 0, 0, 0 };
+ u32 tmp = 0;
+ int status = 0;
+
+ if (dev->power_mode != mode)
+ dev->power_mode = mode;
+ else {
+ cx231xx_info(" setPowerMode::mode = %d, No Change req.\n",
+ mode);
+ return 0;
+ }
+
+ cx231xx_info(" setPowerMode::mode = %d\n", mode);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
+ 4);
+ if (status < 0)
+ return status;
+
+ tmp = *((u32 *) value);
+
+ switch (mode) {
+ case POLARIS_AVMODE_ENXTERNAL_AV:
+
+ tmp &= (~PWR_MODE_MASK);
+
+ tmp |= PWR_AV_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+
+ tmp |= PWR_ISO_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status =
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN,
+ value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+
+ tmp |= POLARIS_AVMODE_ENXTERNAL_AV;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+
+ /* reset state of xceive tuner */
+ dev->xc_fw_load_done = 0;
+ break;
+
+ case POLARIS_AVMODE_ANALOGT_TV:
+
+ tmp &= (~PWR_DEMOD_EN);
+ tmp |= (I2C_DEMOD_EN);
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+
+ if (!(tmp & PWR_TUNER_EN)) {
+ tmp |= (PWR_TUNER_EN);
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+
+ if (!(tmp & PWR_AV_EN)) {
+ tmp |= PWR_AV_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+ if (!(tmp & PWR_ISO_EN)) {
+ tmp |= PWR_ISO_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+
+ if (!(tmp & POLARIS_AVMODE_ANALOGT_TV)) {
+ tmp |= POLARIS_AVMODE_ANALOGT_TV;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+
+ if ((dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
+ (dev->model == CX231XX_BOARD_CNXT_RDU_250)) {
+ /* tuner path to channel 1 from port 3 */
+ cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+
+ if (dev->cx231xx_reset_analog_tuner)
+ dev->cx231xx_reset_analog_tuner(dev);
+ }
+ break;
+
+ case POLARIS_AVMODE_DIGITAL:
+ if (!(tmp & PWR_TUNER_EN)) {
+ tmp |= (PWR_TUNER_EN);
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+ if (!(tmp & PWR_AV_EN)) {
+ tmp |= PWR_AV_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+ if (!(tmp & PWR_ISO_EN)) {
+ tmp |= PWR_ISO_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+
+ tmp |= POLARIS_AVMODE_DIGITAL | I2C_DEMOD_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+
+ if (!(tmp & PWR_DEMOD_EN)) {
+ tmp |= PWR_DEMOD_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+
+ if ((dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
+ (dev->model == CX231XX_BOARD_CNXT_RDU_250)) {
+ /* tuner path to channel 1 from port 3 */
+ cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+
+ if (dev->cx231xx_reset_analog_tuner)
+ dev->cx231xx_reset_analog_tuner(dev);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ msleep(PWR_SLEEP_INTERVAL);
+
+ /* For power saving, only enable Pwr_resetout_n
+ when digital TV is selected. */
+ if (mode == POLARIS_AVMODE_DIGITAL) {
+ tmp |= PWR_RESETOUT_EN;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(PWR_SLEEP_INTERVAL);
+ }
+
+ /* update power control for afe */
+ status = cx231xx_afe_update_power_control(dev, mode);
+
+ /* update power control for i2s_blk */
+ status = cx231xx_i2s_blk_update_power_control(dev, mode);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
+ 4);
+ cx231xx_info(" The data of PWR_CTL_EN register 0x74"
+ "=0x%0x,0x%0x,0x%0x,0x%0x\n",
+ value[0], value[1], value[2], value[3]);
+
+ return status;
+}
+
+int cx231xx_power_suspend(struct cx231xx *dev)
+{
+ u8 value[4] = { 0, 0, 0, 0 };
+ u32 tmp = 0;
+ int status = 0;
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+ value, 4);
+ if (status > 0)
+ return status;
+
+ tmp = *((u32 *) value);
+ tmp &= (~PWR_MODE_MASK);
+
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN,
+ value, 4);
+
+ return status;
+}
+
+/******************************************************************************
+ * S T R E A M C O N T R O L functions *
+ ******************************************************************************/
+int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask)
+{
+ u8 value[4] = { 0x0, 0x0, 0x0, 0x0 };
+ u32 tmp = 0;
+ int status = 0;
+
+ cx231xx_info("cx231xx_start_stream():: ep_mask = %x\n", ep_mask);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
+ value, 4);
+ if (status < 0)
+ return status;
+
+ tmp = *((u32 *) value);
+ tmp |= ep_mask;
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET,
+ value, 4);
+
+ return status;
+}
+
+int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
+{
+ u8 value[4] = { 0x0, 0x0, 0x0, 0x0 };
+ u32 tmp = 0;
+ int status = 0;
+
+ cx231xx_info("cx231xx_stop_stream():: ep_mask = %x\n", ep_mask);
+ status =
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, value, 4);
+ if (status < 0)
+ return status;
+
+ tmp = *((u32 *) value);
+ tmp &= (~ep_mask);
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET,
+ value, 4);
+
+ return status;
+}
+
+int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
+{
+ int status = 0;
+
+ if (dev->udev->speed == USB_SPEED_HIGH) {
+ switch (media_type) {
+ case 81: /* audio */
+ cx231xx_info("%s: Audio enter HANC\n", __func__);
+ status =
+ cx231xx_mode_register(dev, TS_MODE_REG, 0x9300);
+ break;
+
+ case 2: /* vbi */
+ cx231xx_info("%s: set vanc registers\n", __func__);
+ status = cx231xx_mode_register(dev, TS_MODE_REG, 0x300);
+ break;
+
+ case 3: /* sliced cc */
+ cx231xx_info("%s: set hanc registers\n", __func__);
+ status =
+ cx231xx_mode_register(dev, TS_MODE_REG, 0x1300);
+ break;
+
+ case 0: /* video */
+ cx231xx_info("%s: set video registers\n", __func__);
+ status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
+ break;
+
+ case 4: /* ts1 */
+ cx231xx_info("%s: set ts1 registers\n", __func__);
+ status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101);
+ status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400);
+ break;
+ case 6: /* ts1 parallel mode */
+ cx231xx_info("%s: set ts1 parrallel mode registers\n",
+ __func__);
+ status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
+ status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400);
+ break;
+ }
+ } else {
+ status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101);
+ }
+
+ return status;
+}
+
+int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type)
+{
+ int rc;
+ u32 ep_mask = -1;
+ struct pcb_config *pcb_config;
+
+ /* get EP for media type */
+ pcb_config = (struct pcb_config *)&dev->current_pcb_config;
+
+ if (pcb_config->config_num == 1) {
+ switch (media_type) {
+ case 0: /* Video */
+ ep_mask = ENABLE_EP4; /* ep4 [00:1000] */
+ break;
+ case 1: /* Audio */
+ ep_mask = ENABLE_EP3; /* ep3 [00:0100] */
+ break;
+ case 2: /* Vbi */
+ ep_mask = ENABLE_EP5; /* ep5 [01:0000] */
+ break;
+ case 3: /* Sliced_cc */
+ ep_mask = ENABLE_EP6; /* ep6 [10:0000] */
+ break;
+ case 4: /* ts1 */
+ case 6: /* ts1 parallel mode */
+ ep_mask = ENABLE_EP1; /* ep1 [00:0001] */
+ break;
+ case 5: /* ts2 */
+ ep_mask = ENABLE_EP2; /* ep2 [00:0010] */
+ break;
+ }
+
+ } else if (pcb_config->config_num > 1) {
+ switch (media_type) {
+ case 0: /* Video */
+ ep_mask = ENABLE_EP4; /* ep4 [00:1000] */
+ break;
+ case 1: /* Audio */
+ ep_mask = ENABLE_EP3; /* ep3 [00:0100] */
+ break;
+ case 2: /* Vbi */
+ ep_mask = ENABLE_EP5; /* ep5 [01:0000] */
+ break;
+ case 3: /* Sliced_cc */
+ ep_mask = ENABLE_EP6; /* ep6 [10:0000] */
+ break;
+ case 4: /* ts1 */
+ case 6: /* ts1 parallel mode */
+ ep_mask = ENABLE_EP1; /* ep1 [00:0001] */
+ break;
+ case 5: /* ts2 */
+ ep_mask = ENABLE_EP2; /* ep2 [00:0010] */
+ break;
+ }
+
+ }
+
+ if (start) {
+ rc = cx231xx_initialize_stream_xfer(dev, media_type);
+
+ if (rc < 0)
+ return rc;
+
+ /* enable video capture */
+ if (ep_mask > 0)
+ rc = cx231xx_start_stream(dev, ep_mask);
+ } else {
+ /* disable video capture */
+ if (ep_mask > 0)
+ rc = cx231xx_stop_stream(dev, ep_mask);
+ }
+
+ if (dev->mode == CX231XX_ANALOG_MODE)
+ ;/* do any in Analog mode */
+ else
+ ;/* do any in digital mode */
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(cx231xx_capture_start);
+
+/*****************************************************************************
+* G P I O B I T control functions *
+******************************************************************************/
+int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
+{
+ int status = 0;
+
+ status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 0);
+
+ return status;
+}
+
+int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
+{
+ int status = 0;
+
+ status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 1);
+
+ return status;
+}
+
+/*
+* cx231xx_set_gpio_direction
+* Sets the direction of the GPIO pin to input or output
+*
+* Parameters :
+* pin_number : The GPIO Pin number to program the direction for
+* from 0 to 31
+* pin_value : The Direction of the GPIO Pin under reference.
+* 0 = Input direction
+* 1 = Output direction
+*/
+int cx231xx_set_gpio_direction(struct cx231xx *dev,
+ int pin_number, int pin_value)
+{
+ int status = 0;
+ u32 value = 0;
+
+ /* Check for valid pin_number - if 32 , bail out */
+ if (pin_number >= 32)
+ return -EINVAL;
+
+ /* input */
+ if (pin_value == 0)
+ value = dev->gpio_dir & (~(1 << pin_number)); /* clear */
+ else
+ value = dev->gpio_dir | (1 << pin_number);
+
+ status = cx231xx_set_gpio_bit(dev, value, (u8 *) &dev->gpio_val);
+
+ /* cache the value for future */
+ dev->gpio_dir = value;
+
+ return status;
+}
+
+/*
+* cx231xx_set_gpio_value
+* Sets the value of the GPIO pin to Logic high or low. The Pin under
+* reference should ALREADY BE SET IN OUTPUT MODE !!!!!!!!!
+*
+* Parameters :
+* pin_number : The GPIO Pin number to program the direction for
+* pin_value : The value of the GPIO Pin under reference.
+* 0 = set it to 0
+* 1 = set it to 1
+*/
+int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value)
+{
+ int status = 0;
+ u32 value = 0;
+
+ /* Check for valid pin_number - if 0xFF , bail out */
+ if (pin_number >= 32)
+ return -EINVAL;
+
+ /* first do a sanity check - if the Pin is not output, make it output */
+ if ((dev->gpio_dir & (1 << pin_number)) == 0x00) {
+ /* It was in input mode */
+ value = dev->gpio_dir | (1 << pin_number);
+ dev->gpio_dir = value;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *) &dev->gpio_val);
+ value = 0;
+ }
+
+ if (pin_value == 0)
+ value = dev->gpio_val & (~(1 << pin_number));
+ else
+ value = dev->gpio_val | (1 << pin_number);
+
+ /* store the value */
+ dev->gpio_val = value;
+
+ /* toggle bit0 of GP_IO */
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ return status;
+}
+
+/*****************************************************************************
+* G P I O I2C related functions *
+******************************************************************************/
+int cx231xx_gpio_i2c_start(struct cx231xx *dev)
+{
+ int status = 0;
+
+ /* set SCL to output 1 ; set SDA to output 1 */
+ dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+ dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
+
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ if (status < 0)
+ return -EINVAL;
+
+ /* set SCL to output 1; set SDA to output 0 */
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ if (status < 0)
+ return -EINVAL;
+
+ /* set SCL to output 0; set SDA to output 0 */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ if (status < 0)
+ return -EINVAL;
+
+ return status;
+}
+
+int cx231xx_gpio_i2c_end(struct cx231xx *dev)
+{
+ int status = 0;
+
+ /* set SCL to output 0; set SDA to output 0 */
+ dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+ dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ if (status < 0)
+ return -EINVAL;
+
+ /* set SCL to output 1; set SDA to output 0 */
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ if (status < 0)
+ return -EINVAL;
+
+ /* set SCL to input ,release SCL cable control
+ set SDA to input ,release SDA cable control */
+ dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio);
+ dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+
+ status =
+ cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ if (status < 0)
+ return -EINVAL;
+
+ return status;
+}
+
+int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data)
+{
+ int status = 0;
+ u8 i;
+
+ /* set SCL to output ; set SDA to output */
+ dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+ dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+
+ for (i = 0; i < 8; i++) {
+ if (((data << i) & 0x80) == 0) {
+ /* set SCL to output 0; set SDA to output 0 */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+
+ /* set SCL to output 1; set SDA to output 0 */
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+
+ /* set SCL to output 0; set SDA to output 0 */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+ } else {
+ /* set SCL to output 0; set SDA to output 1 */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+
+ /* set SCL to output 1; set SDA to output 1 */
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+
+ /* set SCL to output 0; set SDA to output 1 */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+ }
+ }
+ return status;
+}
+
+int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 * buf)
+{
+ u8 value = 0;
+ int status = 0;
+ u32 gpio_logic_value = 0;
+ u8 i;
+
+ /* read byte */
+ for (i = 0; i < 8; i++) { /* send write I2c addr */
+
+ /* set SCL to output 0; set SDA to input */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+
+ /* set SCL to output 1; set SDA to input */
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+
+ /* get SDA data bit */
+ gpio_logic_value = dev->gpio_val;
+ status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+ if ((dev->gpio_val & (1 << dev->board.tuner_sda_gpio)) != 0)
+ value |= (1 << (8 - i - 1));
+
+ dev->gpio_val = gpio_logic_value;
+ }
+
+ /* set SCL to output 0,finish the read latest SCL signal.
+ !!!set SDA to input, never to modify SDA direction at
+ the same times */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ /* store the value */
+ *buf = value & 0xff;
+
+ return status;
+}
+
+int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
+{
+ int status = 0;
+ u32 gpio_logic_value = 0;
+ int nCnt = 10;
+ int nInit = nCnt;
+
+ /* clock stretch; set SCL to input; set SDA to input;
+ get SCL value till SCL = 1 */
+ dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+ dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio);
+
+ gpio_logic_value = dev->gpio_val;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ do {
+ msleep(2);
+ status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
+ (u8 *)&dev->gpio_val);
+ nCnt--;
+ } while (((dev->gpio_val &
+ (1 << dev->board.tuner_scl_gpio)) == 0) &&
+ (nCnt > 0));
+
+ if (nCnt == 0)
+ cx231xx_info("No ACK after %d msec -GPIO I2C failed!",
+ nInit * 10);
+
+ /* readAck
+ throuth clock stretch ,slave has given a SCL signal,
+ so the SDA data can be directly read. */
+ status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) {
+ dev->gpio_val = gpio_logic_value;
+ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+ status = 0;
+ } else {
+ dev->gpio_val = gpio_logic_value;
+ dev->gpio_val |= (1 << dev->board.tuner_sda_gpio);
+ }
+
+ /* read SDA end, set the SCL to output 0, after this operation,
+ SDA direction can be changed. */
+ dev->gpio_val = gpio_logic_value;
+ dev->gpio_dir |= (1 << dev->board.tuner_scl_gpio);
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ return status;
+}
+
+int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev)
+{
+ int status = 0;
+
+ /* set SDA to ouput */
+ dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ /* set SCL = 0 (output); set SDA = 0 (output) */
+ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ /* set SCL = 1 (output); set SDA = 0 (output) */
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ /* set SCL = 0 (output); set SDA = 0 (output) */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ /* set SDA to input,and then the slave will read data from SDA. */
+ dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ return status;
+}
+
+int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev)
+{
+ int status = 0;
+
+ /* set scl to output ; set sda to input */
+ dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+ dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ /* set scl to output 0; set sda to input */
+ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ /* set scl to output 1; set sda to input */
+ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+ return status;
+}
+
+/*****************************************************************************
+* G P I O I2C related functions *
+******************************************************************************/
+/* cx231xx_gpio_i2c_read
+ * Function to read data from gpio based I2C interface
+ */
+int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
+{
+ int status = 0;
+ int i = 0;
+
+ /* get the lock */
+ mutex_lock(&dev->gpio_i2c_lock);
+
+ /* start */
+ status = cx231xx_gpio_i2c_start(dev);
+
+ /* write dev_addr */
+ status = cx231xx_gpio_i2c_write_byte(dev, (dev_addr << 1) + 1);
+
+ /* readAck */
+ status = cx231xx_gpio_i2c_read_ack(dev);
+
+ /* read data */
+ for (i = 0; i < len; i++) {
+ /* read data */
+ buf[i] = 0;
+ status = cx231xx_gpio_i2c_read_byte(dev, &buf[i]);
+
+ if ((i + 1) != len) {
+ /* only do write ack if we more length */
+ status = cx231xx_gpio_i2c_write_ack(dev);
+ }
+ }
+
+ /* write NAK - inform reads are complete */
+ status = cx231xx_gpio_i2c_write_nak(dev);
+
+ /* write end */
+ status = cx231xx_gpio_i2c_end(dev);
+
+ /* release the lock */
+ mutex_unlock(&dev->gpio_i2c_lock);
+
+ return status;
+}
+
+/* cx231xx_gpio_i2c_write
+ * Function to write data to gpio based I2C interface
+ */
+int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
+{
+ int status = 0;
+ int i = 0;
+
+ /* get the lock */
+ mutex_lock(&dev->gpio_i2c_lock);
+
+ /* start */
+ status = cx231xx_gpio_i2c_start(dev);
+
+ /* write dev_addr */
+ status = cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1);
+
+ /* read Ack */
+ status = cx231xx_gpio_i2c_read_ack(dev);
+
+ for (i = 0; i < len; i++) {
+ /* Write data */
+ status = cx231xx_gpio_i2c_write_byte(dev, buf[i]);
+
+ /* read Ack */
+ status = cx231xx_gpio_i2c_read_ack(dev);
+ }
+
+ /* write End */
+ status = cx231xx_gpio_i2c_end(dev);
+
+ /* release the lock */
+ mutex_unlock(&dev->gpio_i2c_lock);
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-cards.c b/linux/drivers/media/video/cx231xx/cx231xx-cards.c
new file mode 100644
index 000000000..d1872988a
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -0,0 +1,930 @@
+/*
+ cx231xx-cards.c - driver for Conexant Cx23100/101/102
+ USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include "compat.h"
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+#include <media/cx25840.h>
+#include "xc5000.h"
+
+#include "cx231xx.h"
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+
+/* Bitmask marking allocated devices from 0 to CX231XX_MAXBOARDS */
+static unsigned long cx231xx_devused;
+
+/*
+ * Reset sequences for analog/digital modes
+ */
+
+static struct cx231xx_reg_seq RDE250_XCV_TUNER[] = {
+ {0x03, 0x01, 10},
+ {0x03, 0x00, 30},
+ {0x03, 0x01, 10},
+ {-1, -1, -1},
+};
+
+/*
+ * Board definitions
+ */
+struct cx231xx_board cx231xx_boards[] = {
+ [CX231XX_BOARD_UNKNOWN] = {
+ .name = "Unknown CX231xx video grabber",
+ .tuner_type = TUNER_ABSENT,
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }
+ },
+ },
+ [CX231XX_BOARD_CNXT_RDE_250] = {
+ .name = "Conexant Hybrid TV - RDE250",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x02,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }
+ },
+ },
+
+ [CX231XX_BOARD_CNXT_RDU_250] = {
+ .name = "Conexant Hybrid TV - RDU250",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x32,
+ .norm = V4L2_STD_NTSC,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }
+ },
+ },
+};
+const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
+
+/* table of devices that work with this driver */
+struct usb_device_id cx231xx_id_table[] = {
+ {USB_DEVICE(0x0572, 0x5A3C),
+ .driver_info = CX231XX_BOARD_UNKNOWN},
+ {USB_DEVICE(0x0572, 0x58A2),
+ .driver_info = CX231XX_BOARD_CNXT_RDE_250},
+ {USB_DEVICE(0x0572, 0x58A1),
+ .driver_info = CX231XX_BOARD_CNXT_RDU_250},
+ {},
+};
+
+MODULE_DEVICE_TABLE(usb, cx231xx_id_table);
+
+/* cx231xx_tuner_callback
+ * will be used to reset XC5000 tuner using GPIO pin
+ */
+
+int cx231xx_tuner_callback(void *ptr, int component, int command, int arg)
+{
+ int rc = 0;
+ struct cx231xx *dev = ptr;
+
+ if (dev->tuner_type == TUNER_XC5000) {
+ if (command == XC5000_TUNER_RESET) {
+ cx231xx_info
+ ("Tuner CB: RESET: cmd %d : tuner type %d \n",
+ command, dev->tuner_type);
+ cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit,
+ 1);
+ msleep(10);
+ cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit,
+ 0);
+ msleep(330);
+ cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit,
+ 1);
+ msleep(10);
+ }
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(cx231xx_tuner_callback);
+
+static inline void cx231xx_set_model(struct cx231xx *dev)
+{
+ memcpy(&dev->board, &cx231xx_boards[dev->model], sizeof(dev->board));
+}
+
+/* Since cx231xx_pre_card_setup() requires a proper dev->model,
+ * this won't work for boards with generic PCI IDs
+ */
+void cx231xx_pre_card_setup(struct cx231xx *dev)
+{
+
+ cx231xx_set_model(dev);
+
+ cx231xx_info("Identified as %s (card=%d)\n",
+ dev->board.name, dev->model);
+
+ /* set the direction for GPIO pins */
+ cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1);
+ cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1);
+ cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1);
+
+ /* request some modules if any required */
+
+ /* reset the Tuner */
+ cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+
+ /* set the mode to Analog mode initially */
+ cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+
+ /* Unlock device */
+ /* cx231xx_set_mode(dev, CX231XX_SUSPEND); */
+
+}
+
+static void cx231xx_config_tuner(struct cx231xx *dev)
+{
+ struct tuner_setup tun_setup;
+ struct v4l2_frequency f;
+
+ if (dev->tuner_type == TUNER_ABSENT)
+ return;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+ tun_setup.tuner_callback = cx231xx_tuner_callback;
+
+ tuner_call(dev, tuner, s_type_addr, &tun_setup);
+
+#if 0 /* Keep */
+ if (tun_setup.type == TUNER_XC5000) {
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC5000_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = 0;
+ };
+ struct v4l2_priv_tun_config cfg = {
+ .tuner = dev->tuner_type,
+ .priv = &ctrl,
+ };
+ tuner_call(dev, tuner, s_config, &cfg);
+ }
+#endif
+ /* configure tuner */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_ANALOG_TV;
+ f.frequency = 9076; /* just a magic number */
+ dev->ctl_freq = f.frequency;
+ call_all(dev, tuner, s_frequency, &f);
+
+}
+
+/* ----------------------------------------------------------------------- */
+void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir)
+{
+ if (disable_ir) {
+ ir->get_key = NULL;
+ return;
+ }
+
+ /* detect & configure */
+ switch (dev->model) {
+
+ case CX231XX_BOARD_CNXT_RDE_250:
+ break;
+ case CX231XX_BOARD_CNXT_RDU_250:
+ break;
+ default:
+ break;
+ }
+}
+
+void cx231xx_card_setup(struct cx231xx *dev)
+{
+
+ cx231xx_set_model(dev);
+
+ dev->tuner_type = cx231xx_boards[dev->model].tuner_type;
+ if (cx231xx_boards[dev->model].tuner_addr)
+ dev->tuner_addr = cx231xx_boards[dev->model].tuner_addr;
+
+ /* request some modules */
+ if (dev->board.decoder == CX231XX_AVDECODER) {
+ dev->sd_cx25840 =
+ v4l2_i2c_new_subdev(&dev->i2c_bus[0].i2c_adap,
+ "cx25840", "cx25840", 0x88 >> 1);
+ if (dev->sd_cx25840 == NULL)
+ cx231xx_info("cx25840 subdev registration failure\n");
+ cx25840_call(dev, core, init, 0);
+
+ }
+
+ if (dev->board.tuner_type != TUNER_ABSENT) {
+ dev->sd_tuner =
+ v4l2_i2c_new_subdev(&dev->i2c_bus[1].i2c_adap,
+ "tuner", "tuner", 0xc2 >> 1);
+ if (dev->sd_tuner == NULL)
+ cx231xx_info("tuner subdev registration failure\n");
+
+ cx231xx_config_tuner(dev);
+ }
+
+ cx231xx_config_tuner(dev);
+
+#if 0 /* Keep */
+ /* TBD IR will be added later */
+ cx231xx_ir_init(dev);
+#endif
+}
+
+/*
+ * cx231xx_config()
+ * inits registers with sane defaults
+ */
+int cx231xx_config(struct cx231xx *dev)
+{
+ /* TBD need to add cx231xx specific code */
+ dev->mute = 1; /* maybe not the right place... */
+ dev->volume = 0x1f;
+
+ return 0;
+}
+
+/*
+ * cx231xx_config_i2c()
+ * configure i2c attached devices
+ */
+void cx231xx_config_i2c(struct cx231xx *dev)
+{
+ struct v4l2_routing route;
+
+ route.input = INPUT(dev->video_input)->vmux;
+ route.output = 0;
+
+ call_all(dev, video, s_stream, 1);
+}
+
+/*
+ * cx231xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void cx231xx_release_resources(struct cx231xx *dev)
+{
+
+#if 0 /* Keep */ /* TBD IR related */
+ if (dev->ir)
+ cx231xx_ir_fini(dev);
+#endif
+
+ cx231xx_release_analog_resources(dev);
+
+ cx231xx_remove_from_devlist(dev);
+
+ cx231xx_dev_uninit(dev);
+
+ usb_put_dev(dev->udev);
+
+ /* Mark device as unused */
+ cx231xx_devused &= ~(1 << dev->devno);
+}
+
+/*
+ * cx231xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
+ int minor)
+{
+ struct cx231xx *dev = *devhandle;
+ int retval = -ENOMEM;
+ int errCode;
+ unsigned int maxh, maxw;
+
+ dev->udev = udev;
+ mutex_init(&dev->lock);
+ mutex_init(&dev->ctrl_urb_lock);
+ mutex_init(&dev->gpio_i2c_lock);
+
+ spin_lock_init(&dev->video_mode.slock);
+ spin_lock_init(&dev->vbi_mode.slock);
+ spin_lock_init(&dev->sliced_cc_mode.slock);
+
+ init_waitqueue_head(&dev->open);
+ init_waitqueue_head(&dev->wait_frame);
+ init_waitqueue_head(&dev->wait_stream);
+
+ dev->cx231xx_read_ctrl_reg = cx231xx_read_ctrl_reg;
+ dev->cx231xx_write_ctrl_reg = cx231xx_write_ctrl_reg;
+ dev->cx231xx_send_usb_command = cx231xx_send_usb_command;
+ dev->cx231xx_gpio_i2c_read = cx231xx_gpio_i2c_read;
+ dev->cx231xx_gpio_i2c_write = cx231xx_gpio_i2c_write;
+
+ /* Query cx231xx to find what pcb config it is related to */
+ initialize_cx231xx(dev);
+
+ /* Cx231xx pre card setup */
+ cx231xx_pre_card_setup(dev);
+
+ errCode = cx231xx_config(dev);
+ if (errCode) {
+ cx231xx_errdev("error configuring device\n");
+ return -ENOMEM;
+ }
+
+ /* set default norm */
+ dev->norm = dev->board.norm;
+
+ /* register i2c bus */
+ errCode = cx231xx_dev_init(dev);
+ if (errCode < 0) {
+ cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* Do board specific init */
+ cx231xx_card_setup(dev);
+
+ /* configure the device */
+ cx231xx_config_i2c(dev);
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+ /* set default image size */
+ dev->width = maxw;
+ dev->height = maxh;
+ dev->interlaced = 0;
+ dev->hscale = 0;
+ dev->vscale = 0;
+ dev->video_input = 0;
+
+ errCode = cx231xx_config(dev);
+ if (errCode < 0) {
+ cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->video_mode.vidq.active);
+ INIT_LIST_HEAD(&dev->video_mode.vidq.queued);
+
+ /* init vbi dma queues */
+ INIT_LIST_HEAD(&dev->vbi_mode.vidq.active);
+ INIT_LIST_HEAD(&dev->vbi_mode.vidq.queued);
+
+ /* Reset other chips required if they are tied up with GPIO pins */
+
+ cx231xx_add_into_devlist(dev);
+
+ retval = cx231xx_register_analog_devices(dev);
+ if (retval < 0) {
+ cx231xx_release_resources(dev);
+ goto fail_reg_devices;
+ }
+
+ cx231xx_init_extension(dev);
+
+ return 0;
+
+fail_reg_devices:
+ mutex_unlock(&dev->lock);
+ return retval;
+}
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void request_module_async(void *ptr)
+{
+ struct cx231xx *dev = (struct cx231xx *)ptr;
+#else
+static void request_module_async(struct work_struct *work)
+{
+ struct cx231xx *dev = container_of(work,
+ struct cx231xx, request_module_wk);
+#endif
+
+ if (dev->has_alsa_audio)
+ request_module("cx231xx-alsa");
+
+ if (dev->board.has_dvb)
+ request_module("cx231xx-dvb");
+
+}
+
+static void request_modules(struct cx231xx *dev)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&dev->request_module_wk, request_module_async, (void *)dev);
+#else
+ INIT_WORK(&dev->request_module_wk, request_module_async);
+#endif
+ schedule_work(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/*
+ * cx231xx_usb_probe()
+ * checks for supported devices
+ */
+static int cx231xx_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev;
+ struct usb_interface *uif;
+ struct cx231xx *dev = NULL;
+ int retval = -ENODEV;
+ int nr = 0, ifnum;
+ int i, isoc_pipe = 0;
+ char *speed;
+ char descr[255] = "";
+ struct usb_interface *lif = NULL;
+ int skip_interface = 0;
+ struct usb_interface_assoc_descriptor *assoc_desc;
+
+ udev = usb_get_dev(interface_to_usbdev(interface));
+ ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+ if (!ifnum) {
+ /*
+ * Interface number 0 - IR interface
+ */
+ /* Check to see next free device and mark as used */
+ nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
+ cx231xx_devused |= 1 << nr;
+
+ if (nr >= CX231XX_MAXBOARDS) {
+ cx231xx_err(DRIVER_NAME ": Supports only %i cx231xx boards.\n",
+ CX231XX_MAXBOARDS);
+ cx231xx_devused &= ~(1 << nr);
+ return -ENOMEM;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ cx231xx_err(DRIVER_NAME ": out of memory!\n");
+ cx231xx_devused &= ~(1 << nr);
+ return -ENOMEM;
+ }
+
+ snprintf(dev->name, 29, "cx231xx #%d", nr);
+ dev->devno = nr;
+ dev->model = id->driver_info;
+ dev->video_mode.alt = -1;
+ dev->interface_count++;
+
+ /* reset gpio dir and value */
+ dev->gpio_dir = 0;
+ dev->gpio_val = 0;
+ dev->xc_fw_load_done = 0;
+ dev->has_alsa_audio = 1;
+ dev->power_mode = -1;
+
+ /* 0 - vbi ; 1 -sliced cc mode */
+ dev->vbi_or_sliced_cc_mode = 0;
+
+ /* get maximum no.of IAD interfaces */
+ assoc_desc = udev->actconfig->intf_assoc[0];
+ dev->max_iad_interface_count = assoc_desc->bInterfaceCount;
+
+ /* init CIR module TBD */
+
+ /* store the current interface */
+ lif = interface;
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ speed = "1.5";
+ break;
+ case USB_SPEED_UNKNOWN:
+ case USB_SPEED_FULL:
+ speed = "12";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "480";
+ break;
+ default:
+ speed = "unknown";
+ }
+
+ if (udev->manufacturer)
+ strlcpy(descr, udev->manufacturer, sizeof(descr));
+
+ if (udev->product) {
+ if (*descr)
+ strlcat(descr, " ", sizeof(descr));
+ strlcat(descr, udev->product, sizeof(descr));
+ }
+ if (*descr)
+ strlcat(descr, " ", sizeof(descr));
+
+ cx231xx_info("New device %s@ %s Mbps "
+ "(%04x:%04x) with %d interfaces\n",
+ descr,
+ speed,
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ dev->max_iad_interface_count);
+ } else {
+ /* Get dev structure first */
+ dev = usb_get_intfdata(udev->actconfig->interface[0]);
+ if (dev == NULL) {
+ cx231xx_err(DRIVER_NAME ": out of first interface!\n");
+ return -ENODEV;
+ }
+
+ /* store the interface 0 back */
+ lif = udev->actconfig->interface[0];
+
+ /* increment interface count */
+ dev->interface_count++;
+
+ /* get device number */
+ nr = dev->devno;
+
+ /*
+ * set skip interface, for all interfaces but
+ * interface 1 and the last one
+ */
+ if ((ifnum != 1) && ((dev->interface_count - 1)
+ != dev->max_iad_interface_count))
+ skip_interface = 1;
+
+ if (ifnum == 1) {
+ assoc_desc = udev->actconfig->intf_assoc[0];
+ if (assoc_desc->bFirstInterface != ifnum) {
+ cx231xx_err(DRIVER_NAME ": Not found "
+ "matching IAD interface\n");
+ return -ENODEV;
+ }
+ }
+ }
+
+ if (skip_interface)
+ return -ENODEV;
+
+ cx231xx_info("registering interface %d\n", ifnum);
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(lif, dev);
+
+ if ((dev->interface_count - 1) != dev->max_iad_interface_count)
+ return 0;
+
+ /*
+ * AV device initialization - only done at the last interface
+ */
+
+ /* Create v4l2 device */
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "%s-%03d", "cx231xx", nr);
+ retval = v4l2_device_register(&udev->dev, &dev->v4l2_dev);
+ if (retval) {
+ cx231xx_errdev("v4l2_device_register failed\n");
+ cx231xx_devused &= ~(1 << nr);
+ kfree(dev);
+ return -EIO;
+ }
+
+ /* allocate device struct */
+ retval = cx231xx_init_dev(&dev, udev, nr);
+ if (retval) {
+ cx231xx_devused &= ~(1 << dev->devno);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev);
+ return retval;
+ }
+
+ /* compute alternate max packet sizes for video */
+ uif = udev->actconfig->interface[dev->current_pcb_config.
+ hs_config_info[0].interface_info.video_index + 1];
+
+ dev->video_mode.end_point_addr = le16_to_cpu(uif->altsetting[0].
+ endpoint[isoc_pipe].desc.bEndpointAddress);
+
+ dev->video_mode.num_alt = uif->num_altsetting;
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->video_mode.end_point_addr,
+ dev->video_mode.num_alt);
+ dev->video_mode.alt_max_pkt_size =
+ kmalloc(32 * dev->video_mode.num_alt, GFP_KERNEL);
+
+ if (dev->video_mode.alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ cx231xx_devused &= ~(1 << nr);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->video_mode.num_alt; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+ desc.wMaxPacketSize);
+ dev->video_mode.alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->video_mode.alt_max_pkt_size[i]);
+ }
+
+ /* compute alternate max packet sizes for vbi */
+ uif = udev->actconfig->interface[dev->current_pcb_config.
+ hs_config_info[0].interface_info.
+ vanc_index + 1];
+
+ dev->vbi_mode.end_point_addr =
+ le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress);
+
+ dev->vbi_mode.num_alt = uif->num_altsetting;
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->vbi_mode.end_point_addr,
+ dev->vbi_mode.num_alt);
+ dev->vbi_mode.alt_max_pkt_size =
+ kmalloc(32 * dev->vbi_mode.num_alt, GFP_KERNEL);
+
+ if (dev->vbi_mode.alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ cx231xx_devused &= ~(1 << nr);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->vbi_mode.num_alt; i++) {
+ u16 tmp =
+ le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+ desc.wMaxPacketSize);
+ dev->vbi_mode.alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->vbi_mode.alt_max_pkt_size[i]);
+ }
+
+ /* compute alternate max packet sizes for sliced CC */
+ uif = udev->actconfig->interface[dev->current_pcb_config.
+ hs_config_info[0].interface_info.
+ hanc_index + 1];
+
+ dev->sliced_cc_mode.end_point_addr =
+ le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress);
+
+ dev->sliced_cc_mode.num_alt = uif->num_altsetting;
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->sliced_cc_mode.end_point_addr,
+ dev->sliced_cc_mode.num_alt);
+ dev->sliced_cc_mode.alt_max_pkt_size =
+ kmalloc(32 * dev->sliced_cc_mode.num_alt, GFP_KERNEL);
+
+ if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ cx231xx_devused &= ~(1 << nr);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+ desc.wMaxPacketSize);
+ dev->sliced_cc_mode.alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->sliced_cc_mode.alt_max_pkt_size[i]);
+ }
+
+ if (dev->current_pcb_config.ts1_source != 0xff) {
+ /* compute alternate max packet sizes for TS1 */
+ uif = udev->actconfig->interface[dev->current_pcb_config.
+ hs_config_info[0].
+ interface_info.
+ ts1_index + 1];
+
+ dev->ts1_mode.end_point_addr =
+ le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].
+ desc.bEndpointAddress);
+
+ dev->ts1_mode.num_alt = uif->num_altsetting;
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->ts1_mode.end_point_addr,
+ dev->ts1_mode.num_alt);
+ dev->ts1_mode.alt_max_pkt_size =
+ kmalloc(32 * dev->ts1_mode.num_alt, GFP_KERNEL);
+
+ if (dev->ts1_mode.alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ cx231xx_devused &= ~(1 << nr);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->ts1_mode.num_alt; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].
+ endpoint[isoc_pipe].desc.
+ wMaxPacketSize);
+ dev->ts1_mode.alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->ts1_mode.alt_max_pkt_size[i]);
+ }
+ }
+
+ /* load other modules required */
+ request_modules(dev);
+
+ return 0;
+}
+
+/*
+ * cx231xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void cx231xx_usb_disconnect(struct usb_interface *interface)
+{
+ struct cx231xx *dev;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ if (!dev)
+ return;
+
+ if (!dev->udev)
+ return;
+
+ /* delete v4l2 device */
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ /* wait until all current v4l2 io is finished then deallocate
+ resources */
+ mutex_lock(&dev->lock);
+
+ wake_up_interruptible_all(&dev->open);
+
+ if (dev->users) {
+ cx231xx_warn
+ ("device /dev/video%d is open! Deregistration and memory "
+ "deallocation are deferred on close.\n", dev->vdev->num);
+
+ dev->state |= DEV_MISCONFIGURED;
+ cx231xx_uninit_isoc(dev);
+ dev->state |= DEV_DISCONNECTED;
+ wake_up_interruptible(&dev->wait_frame);
+ wake_up_interruptible(&dev->wait_stream);
+ } else {
+ dev->state |= DEV_DISCONNECTED;
+ cx231xx_release_resources(dev);
+ }
+
+ cx231xx_close_extension(dev);
+
+ mutex_unlock(&dev->lock);
+
+ if (!dev->users) {
+ kfree(dev->video_mode.alt_max_pkt_size);
+ kfree(dev->vbi_mode.alt_max_pkt_size);
+ kfree(dev->sliced_cc_mode.alt_max_pkt_size);
+ kfree(dev->ts1_mode.alt_max_pkt_size);
+ kfree(dev);
+ }
+}
+
+static struct usb_driver cx231xx_usb_driver = {
+ .name = "cx231xx",
+ .probe = cx231xx_usb_probe,
+ .disconnect = cx231xx_usb_disconnect,
+ .id_table = cx231xx_id_table,
+};
+
+static int __init cx231xx_module_init(void)
+{
+ int result;
+
+ printk(KERN_INFO DRIVER_NAME " v4l2 driver loaded.\n");
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&cx231xx_usb_driver);
+ if (result)
+ cx231xx_err(DRIVER_NAME
+ " usb_register failed. Error number %d.\n", result);
+
+ return result;
+}
+
+static void __exit cx231xx_module_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&cx231xx_usb_driver);
+}
+
+module_init(cx231xx_module_init);
+module_exit(cx231xx_module_exit);
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h b/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h
new file mode 100644
index 000000000..a6f398a17
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h
@@ -0,0 +1,494 @@
+/*
+ cx231xx_conf-reg.h - driver for Conexant Cx23100/101/102 USB
+ video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _POLARIS_REG_H_
+#define _POLARIS_REG_H_
+
+#define BOARD_CFG_STAT 0x0
+#define TS_MODE_REG 0x4
+#define TS1_CFG_REG 0x8
+#define TS1_LENGTH_REG 0xc
+#define TS2_CFG_REG 0x10
+#define TS2_LENGTH_REG 0x14
+#define EP_MODE_SET 0x18
+#define CIR_PWR_PTN1 0x1c
+#define CIR_PWR_PTN2 0x20
+#define CIR_PWR_PTN3 0x24
+#define CIR_PWR_MASK0 0x28
+#define CIR_PWR_MASK1 0x2c
+#define CIR_PWR_MASK2 0x30
+#define CIR_GAIN 0x34
+#define CIR_CAR_REG 0x38
+#define CIR_OT_CFG1 0x40
+#define CIR_OT_CFG2 0x44
+#define PWR_CTL_EN 0x74
+
+/* Polaris Endpoints capture mask for register EP_MODE_SET */
+#define ENABLE_EP1 0x01 /* Bit[0]=1 */
+#define ENABLE_EP2 0x02 /* Bit[1]=1 */
+#define ENABLE_EP3 0x04 /* Bit[2]=1 */
+#define ENABLE_EP4 0x08 /* Bit[3]=1 */
+#define ENABLE_EP5 0x10 /* Bit[4]=1 */
+#define ENABLE_EP6 0x20 /* Bit[5]=1 */
+
+/* Bit definition for register PWR_CTL_EN */
+#define PWR_MODE_MASK 0x17f
+#define PWR_AV_EN 0x08 /* bit3 */
+#define PWR_ISO_EN 0x40 /* bit6 */
+#define PWR_AV_MODE 0x30 /* bit4,5 */
+#define PWR_TUNER_EN 0x04 /* bit2 */
+#define PWR_DEMOD_EN 0x02 /* bit1 */
+#define I2C_DEMOD_EN 0x01 /* bit0 */
+#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,
+
+};
+
+/* Colibri Registers */
+
+#define SINGLE_ENDED 0x0
+#define LOW_IF 0x4
+#define EU_IF 0x9
+#define US_IF 0xa
+
+#define SUP_BLK_TUNE1 0x00
+#define SUP_BLK_TUNE2 0x01
+#define SUP_BLK_TUNE3 0x02
+#define SUP_BLK_XTAL 0x03
+#define SUP_BLK_PLL1 0x04
+#define SUP_BLK_PLL2 0x05
+#define SUP_BLK_PLL3 0x06
+#define SUP_BLK_REF 0x07
+#define SUP_BLK_PWRDN 0x08
+#define SUP_BLK_TESTPAD 0x09
+#define ADC_COM_INT5_STAB_REF 0x0a
+#define ADC_COM_QUANT 0x0b
+#define ADC_COM_BIAS1 0x0c
+#define ADC_COM_BIAS2 0x0d
+#define ADC_COM_BIAS3 0x0e
+#define TESTBUS_CTRL 0x12
+
+#define FLD_PWRDN_TUNING_BIAS 0x10
+#define FLD_PWRDN_ENABLE_PLL 0x08
+#define FLD_PWRDN_PD_BANDGAP 0x04
+#define FLD_PWRDN_PD_BIAS 0x02
+#define FLD_PWRDN_PD_TUNECK 0x01
+
+
+#define ADC_STATUS_CH1 0x20
+#define ADC_STATUS_CH2 0x40
+#define ADC_STATUS_CH3 0x60
+
+#define ADC_STATUS2_CH1 0x21
+#define ADC_STATUS2_CH2 0x41
+#define ADC_STATUS2_CH3 0x61
+
+#define ADC_CAL_ATEST_CH1 0x22
+#define ADC_CAL_ATEST_CH2 0x42
+#define ADC_CAL_ATEST_CH3 0x62
+
+#define ADC_PWRDN_CLAMP_CH1 0x23
+#define ADC_PWRDN_CLAMP_CH2 0x43
+#define ADC_PWRDN_CLAMP_CH3 0x63
+
+#define ADC_CTRL_DAC23_CH1 0x24
+#define ADC_CTRL_DAC23_CH2 0x44
+#define ADC_CTRL_DAC23_CH3 0x64
+
+#define ADC_CTRL_DAC1_CH1 0x25
+#define ADC_CTRL_DAC1_CH2 0x45
+#define ADC_CTRL_DAC1_CH3 0x65
+
+#define ADC_DCSERVO_DEM_CH1 0x26
+#define ADC_DCSERVO_DEM_CH2 0x46
+#define ADC_DCSERVO_DEM_CH3 0x66
+
+#define ADC_FB_FRCRST_CH1 0x27
+#define ADC_FB_FRCRST_CH2 0x47
+#define ADC_FB_FRCRST_CH3 0x67
+
+#define ADC_INPUT_CH1 0x28
+#define ADC_INPUT_CH2 0x48
+#define ADC_INPUT_CH3 0x68
+#define INPUT_SEL_MASK 0x30 /* [5:4] in_sel */
+
+#define ADC_NTF_PRECLMP_EN_CH1 0x29
+#define ADC_NTF_PRECLMP_EN_CH2 0x49
+#define ADC_NTF_PRECLMP_EN_CH3 0x69
+
+#define ADC_QGAIN_RES_TRM_CH1 0x2a
+#define ADC_QGAIN_RES_TRM_CH2 0x4a
+#define ADC_QGAIN_RES_TRM_CH3 0x6a
+
+#define ADC_SOC_PRECLMP_TERM_CH1 0x2b
+#define ADC_SOC_PRECLMP_TERM_CH2 0x4b
+#define ADC_SOC_PRECLMP_TERM_CH3 0x6b
+
+#define TESTBUS_CTRL_CH1 0x32
+#define TESTBUS_CTRL_CH2 0x52
+#define TESTBUS_CTRL_CH3 0x72
+
+/******************************************************************************
+ * DIF registers *
+ ******************************************************************************/
+#define DIRECT_IF_REVB_BASE 0x00300
+
+/*****************************************************************************/
+#define DIF_PLL_FREQ_WORD (DIRECT_IF_REVB_BASE + 0x00000000)
+/*****************************************************************************/
+#define FLD_DIF_PLL_LOCK 0x80000000
+/* Reserved [30:29] */
+#define FLD_DIF_PLL_FREE_RUN 0x10000000
+#define FLD_DIF_PLL_FREQ 0x0fffffff
+
+/*****************************************************************************/
+#define DIF_PLL_CTRL (DIRECT_IF_REVB_BASE + 0x00000004)
+/*****************************************************************************/
+#define FLD_DIF_KD_PD 0xff000000
+/* Reserved [23:20] */
+#define FLD_DIF_KDS_PD 0x000f0000
+#define FLD_DIF_KI_PD 0x0000ff00
+/* Reserved [7:4] */
+#define FLD_DIF_KIS_PD 0x0000000f
+
+/*****************************************************************************/
+#define DIF_PLL_CTRL1 (DIRECT_IF_REVB_BASE + 0x00000008)
+/*****************************************************************************/
+#define FLD_DIF_KD_FD 0xff000000
+/* Reserved [23:20] */
+#define FLD_DIF_KDS_FD 0x000f0000
+#define FLD_DIF_KI_FD 0x0000ff00
+#define FLD_DIF_SIG_PROP_SZ 0x000000f0
+#define FLD_DIF_KIS_FD 0x0000000f
+
+/*****************************************************************************/
+#define DIF_PLL_CTRL2 (DIRECT_IF_REVB_BASE + 0x0000000c)
+/*****************************************************************************/
+#define FLD_DIF_PLL_AGC_REF 0xfff00000
+#define FLD_DIF_PLL_AGC_KI 0x000f0000
+/* Reserved [15] */
+#define FLD_DIF_FREQ_LIMIT 0x00007000
+#define FLD_DIF_K_FD 0x00000f00
+#define FLD_DIF_DOWNSMPL_FD 0x000000ff
+
+/*****************************************************************************/
+#define DIF_PLL_CTRL3 (DIRECT_IF_REVB_BASE + 0x00000010)
+/*****************************************************************************/
+/* Reserved [31:16] */
+#define FLD_DIF_PLL_AGC_EN 0x00008000
+/* Reserved [14:12] */
+#define FLD_DIF_PLL_MAN_GAIN 0x00000fff
+
+/*****************************************************************************/
+#define DIF_AGC_IF_REF (DIRECT_IF_REVB_BASE + 0x00000014)
+/*****************************************************************************/
+#define FLD_DIF_K_AGC_RF 0xf0000000
+#define FLD_DIF_K_AGC_IF 0x0f000000
+#define FLD_DIF_K_AGC_INT 0x00f00000
+/* Reserved [19:12] */
+#define FLD_DIF_IF_REF 0x00000fff
+
+/*****************************************************************************/
+#define DIF_AGC_CTRL_IF (DIRECT_IF_REVB_BASE + 0x00000018)
+/*****************************************************************************/
+#define FLD_DIF_IF_MAX 0xff000000
+#define FLD_DIF_IF_MIN 0x00ff0000
+#define FLD_DIF_IF_AGC 0x0000ffff
+
+/*****************************************************************************/
+#define DIF_AGC_CTRL_INT (DIRECT_IF_REVB_BASE + 0x0000001c)
+/*****************************************************************************/
+#define FLD_DIF_INT_MAX 0xff000000
+#define FLD_DIF_INT_MIN 0x00ff0000
+#define FLD_DIF_INT_AGC 0x0000ffff
+
+/*****************************************************************************/
+#define DIF_AGC_CTRL_RF (DIRECT_IF_REVB_BASE + 0x00000020)
+/*****************************************************************************/
+#define FLD_DIF_RF_MAX 0xff000000
+#define FLD_DIF_RF_MIN 0x00ff0000
+#define FLD_DIF_RF_AGC 0x0000ffff
+
+/*****************************************************************************/
+#define DIF_AGC_IF_INT_CURRENT (DIRECT_IF_REVB_BASE + 0x00000024)
+/*****************************************************************************/
+#define FLD_DIF_IF_AGC_IN 0xffff0000
+#define FLD_DIF_INT_AGC_IN 0x0000ffff
+
+/*****************************************************************************/
+#define DIF_AGC_RF_CURRENT (DIRECT_IF_REVB_BASE + 0x00000028)
+/*****************************************************************************/
+/* Reserved [31:16] */
+#define FLD_DIF_RF_AGC_IN 0x0000ffff
+
+/*****************************************************************************/
+#define DIF_VIDEO_AGC_CTRL (DIRECT_IF_REVB_BASE + 0x0000002c)
+/*****************************************************************************/
+#define FLD_DIF_AFD 0xc0000000
+#define FLD_DIF_K_VID_AGC 0x30000000
+#define FLD_DIF_LINE_LENGTH 0x0fff0000
+#define FLD_DIF_AGC_GAIN 0x0000ffff
+
+/*****************************************************************************/
+#define DIF_VID_AUD_OVERRIDE (DIRECT_IF_REVB_BASE + 0x00000030)
+/*****************************************************************************/
+#define FLD_DIF_AUDIO_AGC_OVERRIDE 0x80000000
+/* Reserved [30:30] */
+#define FLD_DIF_AUDIO_MAN_GAIN 0x3f000000
+/* Reserved [23:17] */
+#define FLD_DIF_VID_AGC_OVERRIDE 0x00010000
+#define FLD_DIF_VID_MAN_GAIN 0x0000ffff
+
+/*****************************************************************************/
+#define DIF_AV_SEP_CTRL (DIRECT_IF_REVB_BASE + 0x00000034)
+/*****************************************************************************/
+#define FLD_DIF_LPF_FREQ 0xc0000000
+#define FLD_DIF_AV_PHASE_INC 0x3f000000
+#define FLD_DIF_AUDIO_FREQ 0x00ffffff
+
+/*****************************************************************************/
+#define DIF_COMP_FLT_CTRL (DIRECT_IF_REVB_BASE + 0x00000038)
+/*****************************************************************************/
+/* Reserved [31:24] */
+#define FLD_DIF_IIR23_R2 0x00ff0000
+#define FLD_DIF_IIR23_R1 0x0000ff00
+#define FLD_DIF_IIR1_R1 0x000000ff
+
+/*****************************************************************************/
+#define DIF_MISC_CTRL (DIRECT_IF_REVB_BASE + 0x0000003c)
+/*****************************************************************************/
+#define FLD_DIF_DIF_BYPASS 0x80000000
+#define FLD_DIF_FM_NYQ_GAIN 0x40000000
+#define FLD_DIF_RF_AGC_ENA 0x20000000
+#define FLD_DIF_INT_AGC_ENA 0x10000000
+#define FLD_DIF_IF_AGC_ENA 0x08000000
+#define FLD_DIF_FORCE_RF_IF_LOCK 0x04000000
+#define FLD_DIF_VIDEO_AGC_ENA 0x02000000
+#define FLD_DIF_RF_AGC_INV 0x01000000
+#define FLD_DIF_INT_AGC_INV 0x00800000
+#define FLD_DIF_IF_AGC_INV 0x00400000
+#define FLD_DIF_SPEC_INV 0x00200000
+#define FLD_DIF_AUD_FULL_BW 0x00100000
+#define FLD_DIF_AUD_SRC_SEL 0x00080000
+/* Reserved [18] */
+#define FLD_DIF_IF_FREQ 0x00030000
+/* Reserved [15:14] */
+#define FLD_DIF_TIP_OFFSET 0x00003f00
+/* Reserved [7:5] */
+#define FLD_DIF_DITHER_ENA 0x00000010
+/* Reserved [3:1] */
+#define FLD_DIF_RF_IF_LOCK 0x00000001
+
+/*****************************************************************************/
+#define DIF_SRC_PHASE_INC (DIRECT_IF_REVB_BASE + 0x00000040)
+/*****************************************************************************/
+/* Reserved [31:29] */
+#define FLD_DIF_PHASE_INC 0x1fffffff
+
+/*****************************************************************************/
+#define DIF_SRC_GAIN_CONTROL (DIRECT_IF_REVB_BASE + 0x00000044)
+/*****************************************************************************/
+/* Reserved [31:16] */
+#define FLD_DIF_SRC_KI 0x0000ff00
+#define FLD_DIF_SRC_KD 0x000000ff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF01 (DIRECT_IF_REVB_BASE + 0x00000048)
+/*****************************************************************************/
+/* Reserved [31:19] */
+#define FLD_DIF_BPF_COEFF_0 0x00070000
+/* Reserved [15:4] */
+#define FLD_DIF_BPF_COEFF_1 0x0000000f
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF23 (DIRECT_IF_REVB_BASE + 0x0000004c)
+/*****************************************************************************/
+/* Reserved [31:22] */
+#define FLD_DIF_BPF_COEFF_2 0x003f0000
+/* Reserved [15:7] */
+#define FLD_DIF_BPF_COEFF_3 0x0000007f
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF45 (DIRECT_IF_REVB_BASE + 0x00000050)
+/*****************************************************************************/
+/* Reserved [31:24] */
+#define FLD_DIF_BPF_COEFF_4 0x00ff0000
+/* Reserved [15:8] */
+#define FLD_DIF_BPF_COEFF_5 0x000000ff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF67 (DIRECT_IF_REVB_BASE + 0x00000054)
+/*****************************************************************************/
+/* Reserved [31:25] */
+#define FLD_DIF_BPF_COEFF_6 0x01ff0000
+/* Reserved [15:9] */
+#define FLD_DIF_BPF_COEFF_7 0x000001ff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF89 (DIRECT_IF_REVB_BASE + 0x00000058)
+/*****************************************************************************/
+/* Reserved [31:26] */
+#define FLD_DIF_BPF_COEFF_8 0x03ff0000
+/* Reserved [15:10] */
+#define FLD_DIF_BPF_COEFF_9 0x000003ff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF1011 (DIRECT_IF_REVB_BASE + 0x0000005c)
+/*****************************************************************************/
+/* Reserved [31:27] */
+#define FLD_DIF_BPF_COEFF_10 0x07ff0000
+/* Reserved [15:11] */
+#define FLD_DIF_BPF_COEFF_11 0x000007ff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF1213 (DIRECT_IF_REVB_BASE + 0x00000060)
+/*****************************************************************************/
+/* Reserved [31:27] */
+#define FLD_DIF_BPF_COEFF_12 0x07ff0000
+/* Reserved [15:12] */
+#define FLD_DIF_BPF_COEFF_13 0x00000fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF1415 (DIRECT_IF_REVB_BASE + 0x00000064)
+/*****************************************************************************/
+/* Reserved [31:28] */
+#define FLD_DIF_BPF_COEFF_14 0x0fff0000
+/* Reserved [15:12] */
+#define FLD_DIF_BPF_COEFF_15 0x00000fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF1617 (DIRECT_IF_REVB_BASE + 0x00000068)
+/*****************************************************************************/
+/* Reserved [31:29] */
+#define FLD_DIF_BPF_COEFF_16 0x1fff0000
+/* Reserved [15:13] */
+#define FLD_DIF_BPF_COEFF_17 0x00001fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF1819 (DIRECT_IF_REVB_BASE + 0x0000006c)
+/*****************************************************************************/
+/* Reserved [31:29] */
+#define FLD_DIF_BPF_COEFF_18 0x1fff0000
+/* Reserved [15:13] */
+#define FLD_DIF_BPF_COEFF_19 0x00001fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF2021 (DIRECT_IF_REVB_BASE + 0x00000070)
+/*****************************************************************************/
+/* Reserved [31:29] */
+#define FLD_DIF_BPF_COEFF_20 0x1fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_21 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF2223 (DIRECT_IF_REVB_BASE + 0x00000074)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_22 0x3fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_23 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF2425 (DIRECT_IF_REVB_BASE + 0x00000078)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_24 0x3fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_25 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF2627 (DIRECT_IF_REVB_BASE + 0x0000007c)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_26 0x3fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_27 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF2829 (DIRECT_IF_REVB_BASE + 0x00000080)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_28 0x3fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_29 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF3031 (DIRECT_IF_REVB_BASE + 0x00000084)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_30 0x3fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_31 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF3233 (DIRECT_IF_REVB_BASE + 0x00000088)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_32 0x3fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_33 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF3435 (DIRECT_IF_REVB_BASE + 0x0000008c)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_34 0x3fff0000
+/* Reserved [15:14] */
+#define FLD_DIF_BPF_COEFF_35 0x00003fff
+
+/*****************************************************************************/
+#define DIF_BPF_COEFF36 (DIRECT_IF_REVB_BASE + 0x00000090)
+/*****************************************************************************/
+/* Reserved [31:30] */
+#define FLD_DIF_BPF_COEFF_36 0x3fff0000
+/* Reserved [15:0] */
+
+/*****************************************************************************/
+#define DIF_RPT_VARIANCE (DIRECT_IF_REVB_BASE + 0x00000094)
+/*****************************************************************************/
+/* Reserved [31:20] */
+#define FLD_DIF_RPT_VARIANCE 0x000fffff
+
+/*****************************************************************************/
+#define DIF_SOFT_RST_CTRL_REVB (DIRECT_IF_REVB_BASE + 0x00000098)
+/*****************************************************************************/
+/* Reserved [31:8] */
+#define FLD_DIF_DIF_SOFT_RST 0x00000080
+#define FLD_DIF_DIF_REG_RST_MSK 0x00000040
+#define FLD_DIF_AGC_RST_MSK 0x00000020
+#define FLD_DIF_CMP_RST_MSK 0x00000010
+#define FLD_DIF_AVS_RST_MSK 0x00000008
+#define FLD_DIF_NYQ_RST_MSK 0x00000004
+#define FLD_DIF_DIF_SRC_RST_MSK 0x00000002
+#define FLD_DIF_PLL_RST_MSK 0x00000001
+
+/*****************************************************************************/
+#define DIF_PLL_FREQ_ERR (DIRECT_IF_REVB_BASE + 0x0000009c)
+/*****************************************************************************/
+/* Reserved [31:25] */
+#define FLD_DIF_CTL_IP 0x01ffffff
+
+#endif
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-core.c b/linux/drivers/media/video/cx231xx/cx231xx-core.c
new file mode 100644
index 000000000..70478aa8b
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-core.c
@@ -0,0 +1,1231 @@
+/*
+ cx231xx-core.c - driver for Conexant Cx23100/101/102
+ USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
+
+#include "cx231xx.h"
+#include "cx231xx-reg.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+static unsigned int core_debug;
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
+
+#define cx231xx_coredbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int reg_debug;
+module_param(reg_debug, int, 0644);
+MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
+
+#define cx231xx_regdbg(fmt, arg...) do {\
+ if (reg_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+static int alt = CX231XX_PINOUT;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+#define cx231xx_isocdbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+/*****************************************************************
+* Device control list functions *
+******************************************************************/
+
+static LIST_HEAD(cx231xx_devlist);
+static DEFINE_MUTEX(cx231xx_devlist_mutex);
+
+struct cx231xx *cx231xx_get_device(int minor,
+ enum v4l2_buf_type *fh_type, int *has_radio)
+{
+ struct cx231xx *h, *dev = NULL;
+
+ *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ *has_radio = 0;
+
+ mutex_lock(&cx231xx_devlist_mutex);
+ list_for_each_entry(h, &cx231xx_devlist, devlist) {
+ if (h->vdev->minor == minor)
+ dev = h;
+ if (h->vbi_dev->minor == minor) {
+ dev = h;
+ *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ }
+ if (h->radio_dev && h->radio_dev->minor == minor) {
+ dev = h;
+ *has_radio = 1;
+ }
+ }
+ mutex_unlock(&cx231xx_devlist_mutex);
+
+ return dev;
+}
+
+/*
+ * cx231xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void cx231xx_remove_from_devlist(struct cx231xx *dev)
+{
+ mutex_lock(&cx231xx_devlist_mutex);
+ list_del(&dev->devlist);
+ mutex_unlock(&cx231xx_devlist_mutex);
+};
+
+void cx231xx_add_into_devlist(struct cx231xx *dev)
+{
+ mutex_lock(&cx231xx_devlist_mutex);
+ list_add_tail(&dev->devlist, &cx231xx_devlist);
+ mutex_unlock(&cx231xx_devlist_mutex);
+};
+
+static LIST_HEAD(cx231xx_extension_devlist);
+static DEFINE_MUTEX(cx231xx_extension_devlist_lock);
+
+int cx231xx_register_extension(struct cx231xx_ops *ops)
+{
+ struct cx231xx *dev = NULL;
+
+ mutex_lock(&cx231xx_devlist_mutex);
+ mutex_lock(&cx231xx_extension_devlist_lock);
+ list_add_tail(&ops->next, &cx231xx_extension_devlist);
+ list_for_each_entry(dev, &cx231xx_devlist, devlist) {
+ if (dev)
+ ops->init(dev);
+ }
+ printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name);
+ mutex_unlock(&cx231xx_extension_devlist_lock);
+ mutex_unlock(&cx231xx_devlist_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(cx231xx_register_extension);
+
+void cx231xx_unregister_extension(struct cx231xx_ops *ops)
+{
+ struct cx231xx *dev = NULL;
+
+ mutex_lock(&cx231xx_devlist_mutex);
+ list_for_each_entry(dev, &cx231xx_devlist, devlist) {
+ if (dev)
+ ops->fini(dev);
+ }
+
+ mutex_lock(&cx231xx_extension_devlist_lock);
+ printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name);
+ list_del(&ops->next);
+ mutex_unlock(&cx231xx_extension_devlist_lock);
+ mutex_unlock(&cx231xx_devlist_mutex);
+}
+EXPORT_SYMBOL(cx231xx_unregister_extension);
+
+void cx231xx_init_extension(struct cx231xx *dev)
+{
+ struct cx231xx_ops *ops = NULL;
+
+ mutex_lock(&cx231xx_extension_devlist_lock);
+ if (!list_empty(&cx231xx_extension_devlist)) {
+ list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
+ if (ops->init)
+ ops->init(dev);
+ }
+ }
+ mutex_unlock(&cx231xx_extension_devlist_lock);
+}
+
+void cx231xx_close_extension(struct cx231xx *dev)
+{
+ struct cx231xx_ops *ops = NULL;
+
+ mutex_lock(&cx231xx_extension_devlist_lock);
+ if (!list_empty(&cx231xx_extension_devlist)) {
+ list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
+ if (ops->fini)
+ ops->fini(dev);
+ }
+ }
+ mutex_unlock(&cx231xx_extension_devlist_lock);
+}
+
+/****************************************************************
+* U S B related functions *
+*****************************************************************/
+int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
+ struct cx231xx_i2c_xfer_data *req_data)
+{
+ int status = 0;
+ struct cx231xx *dev = i2c_bus->dev;
+ struct VENDOR_REQUEST_IN ven_req;
+
+ u8 saddr_len = 0;
+ u8 _i2c_period = 0;
+ u8 _i2c_nostop = 0;
+ u8 _i2c_reserve = 0;
+
+ /* Get the I2C period, nostop and reserve parameters */
+ _i2c_period = i2c_bus->i2c_period;
+ _i2c_nostop = i2c_bus->i2c_nostop;
+ _i2c_reserve = i2c_bus->i2c_reserve;
+
+ saddr_len = req_data->saddr_len;
+
+ /* Set wValue */
+ if (saddr_len == 1) /* need check saddr_len == 0 */
+ ven_req.wValue =
+ req_data->
+ dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 |
+ _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6;
+ else
+ ven_req.wValue =
+ req_data->
+ dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 |
+ _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6;
+
+ /* set channel number */
+ if (req_data->direction & I2C_M_RD) {
+ /* channel number, for read,spec required channel_num +4 */
+ ven_req.bRequest = i2c_bus->nr + 4;
+ } else
+ ven_req.bRequest = i2c_bus->nr; /* channel number, */
+
+ /* set index value */
+ switch (saddr_len) {
+ case 0:
+ ven_req.wIndex = 0; /* need check */
+ break;
+ case 1:
+ ven_req.wIndex = (req_data->saddr_dat & 0xff);
+ break;
+ case 2:
+ ven_req.wIndex = req_data->saddr_dat;
+ break;
+ }
+
+ /* set wLength value */
+ ven_req.wLength = req_data->buf_size;
+
+ /* set bData value */
+ ven_req.bData = 0;
+
+ /* set the direction */
+ if (req_data->direction) {
+ ven_req.direction = USB_DIR_IN;
+ memset(req_data->p_buffer, 0x00, ven_req.wLength);
+ } else
+ ven_req.direction = USB_DIR_OUT;
+
+ /* set the buffer for read / write */
+ ven_req.pBuff = req_data->p_buffer;
+
+#if 0
+ {
+ int i = 0;
+
+ cx231xx_isocdbg(": USB Control Pipe Request: I2C Bus#%d\n",
+ i2c_bus->nr);
+ cx231xx_isocdbg("bRequest = %x : ", ven_req.bRequest);
+ cx231xx_isocdbg("wValue = %x : ", ven_req.wValue);
+ cx231xx_isocdbg("wIndex = %x : ", ven_req.wIndex);
+ cx231xx_isocdbg("wLength = %x\n", ven_req.wLength);
+ cx231xx_isocdbg("pBuff : ");
+ for (i = 0; i < ven_req.wLength; i++) {
+ cx231xx_isocdbg(" %2x", ven_req.pBuff[i]);
+ if ((i > 0) && (i % 10 == 0))
+ cx231xx_isocdbg("\n ");
+ }
+ cx231xx_isocdbg("\n\n");
+ }
+#endif
+
+ /* call common vendor command request */
+ status = cx231xx_send_vendor_cmd(dev, &ven_req);
+ if (status < 0) {
+ cx231xx_info
+ ("UsbInterface::sendCommand, failed with status -%d\n",
+ status);
+ }
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_send_usb_command);
+
+/*
+ * cx231xx_read_ctrl_reg()
+ * reads data from the usb device specifying bRequest and wValue
+ */
+int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
+ char *buf, int len)
+{
+ u8 val = 0;
+ int ret;
+ int pipe = usb_rcvctrlpipe(dev->udev, 0);
+
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
+ if (len > URB_MAX_CTRL_SIZE)
+ return -EINVAL;
+
+ switch (len) {
+ case 1:
+ val = ENABLE_ONE_BYTE;
+ break;
+ case 2:
+ val = ENABLE_TWE_BYTE;
+ break;
+ case 3:
+ val = ENABLE_THREE_BYTE;
+ break;
+ case 4:
+ val = ENABLE_FOUR_BYTE;
+ break;
+ default:
+ val = 0xFF; /* invalid option */
+ }
+
+ if (val == 0xFF)
+ return -EINVAL;
+
+ if (reg_debug) {
+ cx231xx_isocdbg("(pipe 0x%08x): "
+ "IN: %02x %02x %02x %02x %02x %02x %02x %02x ",
+ pipe,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, val,
+ reg & 0xff, reg >> 8, len & 0xff, len >> 8);
+ }
+
+ mutex_lock(&dev->ctrl_urb_lock);
+ ret = usb_control_msg(dev->udev, pipe, req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, reg, dev->urb_buf, len, HZ);
+ if (ret < 0) {
+ cx231xx_isocdbg(" failed!\n");
+ /* mutex_unlock(&dev->ctrl_urb_lock); */
+ return ret;
+ }
+
+ if (len)
+ memcpy(buf, dev->urb_buf, len);
+
+ mutex_unlock(&dev->ctrl_urb_lock);
+
+ if (reg_debug) {
+ int byte;
+
+ cx231xx_isocdbg("<<<");
+ for (byte = 0; byte < len; byte++)
+ cx231xx_isocdbg(" %02x", (unsigned char)buf[byte]);
+ cx231xx_isocdbg("\n");
+ }
+
+ return ret;
+}
+
+int cx231xx_send_vendor_cmd(struct cx231xx *dev,
+ struct VENDOR_REQUEST_IN *ven_req)
+{
+ int ret;
+ int pipe = 0;
+
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
+ if ((ven_req->wLength > URB_MAX_CTRL_SIZE))
+ return -EINVAL;
+
+ if (ven_req->direction)
+ pipe = usb_rcvctrlpipe(dev->udev, 0);
+ else
+ pipe = usb_sndctrlpipe(dev->udev, 0);
+
+ if (reg_debug) {
+ int byte;
+
+ cx231xx_isocdbg("(pipe 0x%08x): "
+ "OUT: %02x %02x %02x %04x %04x %04x >>>",
+ pipe,
+ ven_req->
+ direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ ven_req->bRequest, 0, ven_req->wValue,
+ ven_req->wIndex, ven_req->wLength);
+
+ for (byte = 0; byte < ven_req->wLength; byte++)
+ cx231xx_isocdbg(" %02x",
+ (unsigned char)ven_req->pBuff[byte]);
+ cx231xx_isocdbg("\n");
+ }
+
+ mutex_lock(&dev->ctrl_urb_lock);
+ ret = usb_control_msg(dev->udev, pipe, ven_req->bRequest,
+ ven_req->
+ direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ ven_req->wValue, ven_req->wIndex, ven_req->pBuff,
+ ven_req->wLength, HZ);
+ mutex_unlock(&dev->ctrl_urb_lock);
+
+ return ret;
+}
+
+/*
+ * cx231xx_write_ctrl_reg()
+ * sends data to the usb device, specifying bRequest
+ */
+int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, char *buf,
+ int len)
+{
+ u8 val = 0;
+ int ret;
+ int pipe = usb_sndctrlpipe(dev->udev, 0);
+
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
+ if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
+ return -EINVAL;
+
+ switch (len) {
+ case 1:
+ val = ENABLE_ONE_BYTE;
+ break;
+ case 2:
+ val = ENABLE_TWE_BYTE;
+ break;
+ case 3:
+ val = ENABLE_THREE_BYTE;
+ break;
+ case 4:
+ val = ENABLE_FOUR_BYTE;
+ break;
+ default:
+ val = 0xFF; /* invalid option */
+ }
+
+ if (val == 0xFF)
+ return -EINVAL;
+
+ if (reg_debug) {
+ int byte;
+
+ cx231xx_isocdbg("(pipe 0x%08x): "
+ "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
+ pipe,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, val, reg & 0xff,
+ reg >> 8, len & 0xff, len >> 8);
+
+ for (byte = 0; byte < len; byte++)
+ cx231xx_isocdbg(" %02x", (unsigned char)buf[byte]);
+ cx231xx_isocdbg("\n");
+ }
+
+ mutex_lock(&dev->ctrl_urb_lock);
+ memcpy(dev->urb_buf, buf, len);
+ ret = usb_control_msg(dev->udev, pipe, req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, reg, dev->urb_buf, len, HZ);
+ mutex_unlock(&dev->ctrl_urb_lock);
+
+ return ret;
+}
+
+/****************************************************************
+* USB Alternate Setting functions *
+*****************************************************************/
+
+int cx231xx_set_video_alternate(struct cx231xx *dev)
+{
+ int errCode, prev_alt = dev->video_mode.alt;
+ unsigned int min_pkt_size = dev->width * 2 + 4;
+ u32 usb_interface_index = 0;
+
+ /* When image size is bigger than a certain value,
+ the frame size should be increased, otherwise, only
+ green screen will be received.
+ */
+ if (dev->width * 2 * dev->height > 720 * 240 * 2)
+ min_pkt_size *= 2;
+
+ if (dev->width > 360) {
+ /* resolutions: 720,704,640 */
+ dev->video_mode.alt = 3;
+ } else if (dev->width > 180) {
+ /* resolutions: 360,352,320,240 */
+ dev->video_mode.alt = 2;
+ } else if (dev->width > 0) {
+ /* resolutions: 180,176,160,128,88 */
+ dev->video_mode.alt = 1;
+ } else {
+ /* Change to alt0 BULK to release USB bandwidth */
+ dev->video_mode.alt = 0;
+ }
+
+ /* Get the correct video interface Index */
+ usb_interface_index =
+ dev->current_pcb_config.hs_config_info[0].interface_info.
+ video_index + 1;
+
+ if (dev->video_mode.alt != prev_alt) {
+ cx231xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->video_mode.alt);
+ dev->video_mode.max_pkt_size =
+ dev->video_mode.alt_max_pkt_size[dev->video_mode.alt];
+ cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->video_mode.alt,
+ dev->video_mode.max_pkt_size);
+ cx231xx_info
+ (" setting alt %d with wMaxPktSize=%u , Interface = %d\n",
+ dev->video_mode.alt, dev->video_mode.max_pkt_size,
+ usb_interface_index);
+ errCode =
+ usb_set_interface(dev->udev, usb_interface_index,
+ dev->video_mode.alt);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("cannot change alt number to %d (error=%i)\n",
+ dev->video_mode.alt, errCode);
+ return errCode;
+ }
+ }
+ return 0;
+}
+
+int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
+{
+ int status = 0;
+ u32 usb_interface_index = 0;
+ u32 max_pkt_size = 0;
+
+ switch (index) {
+ case INDEX_TS1:
+ usb_interface_index =
+ dev->current_pcb_config.hs_config_info[0].interface_info.
+ ts1_index + 1;
+ dev->video_mode.alt = alt;
+ if (dev->ts1_mode.alt_max_pkt_size != NULL)
+ max_pkt_size = dev->ts1_mode.max_pkt_size =
+ dev->ts1_mode.alt_max_pkt_size[dev->ts1_mode.alt];
+ break;
+ case INDEX_TS2:
+ usb_interface_index =
+ dev->current_pcb_config.hs_config_info[0].interface_info.
+ ts2_index + 1;
+ break;
+ case INDEX_AUDIO:
+ usb_interface_index =
+ dev->current_pcb_config.hs_config_info[0].interface_info.
+ audio_index + 1;
+ dev->adev.alt = alt;
+ if (dev->adev.alt_max_pkt_size != NULL)
+ max_pkt_size = dev->adev.max_pkt_size =
+ dev->adev.alt_max_pkt_size[dev->adev.alt];
+ break;
+ case INDEX_VIDEO:
+ usb_interface_index =
+ dev->current_pcb_config.hs_config_info[0].interface_info.
+ video_index + 1;
+ dev->video_mode.alt = alt;
+ if (dev->video_mode.alt_max_pkt_size != NULL)
+ max_pkt_size = dev->video_mode.max_pkt_size =
+ dev->video_mode.alt_max_pkt_size[dev->video_mode.
+ alt];
+ break;
+ case INDEX_VANC:
+ usb_interface_index =
+ dev->current_pcb_config.hs_config_info[0].interface_info.
+ vanc_index + 1;
+ dev->vbi_mode.alt = alt;
+ if (dev->vbi_mode.alt_max_pkt_size != NULL)
+ max_pkt_size = dev->vbi_mode.max_pkt_size =
+ dev->vbi_mode.alt_max_pkt_size[dev->vbi_mode.alt];
+ break;
+ case INDEX_HANC:
+ usb_interface_index =
+ dev->current_pcb_config.hs_config_info[0].interface_info.
+ hanc_index + 1;
+ dev->sliced_cc_mode.alt = alt;
+ if (dev->sliced_cc_mode.alt_max_pkt_size != NULL)
+ max_pkt_size = dev->sliced_cc_mode.max_pkt_size =
+ dev->sliced_cc_mode.alt_max_pkt_size[dev->
+ sliced_cc_mode.
+ alt];
+ break;
+ default:
+ break;
+ }
+
+ if (alt > 0 && max_pkt_size == 0) {
+ cx231xx_errdev
+ ("can't change interface %d alt no. to %d: Max. Pkt size = 0\n",
+ usb_interface_index, alt);
+ return -1;
+ }
+
+ cx231xx_info
+ (" setting alternate %d with wMaxPacketSize=%u , Interface = %d\n",
+ alt, max_pkt_size, usb_interface_index);
+
+ if (usb_interface_index > 0) {
+ status = usb_set_interface(dev->udev, usb_interface_index, alt);
+ if (status < 0) {
+ cx231xx_errdev
+ ("can't change interface %d alt no. to %d (err=%i)\n",
+ usb_interface_index, alt, status);
+ return status;
+ }
+ }
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_set_alt_setting);
+
+int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio)
+{
+ int rc = 0;
+
+ if (!gpio)
+ return rc;
+
+ /* Send GPIO reset sequences specified at board entry */
+ while (gpio->sleep >= 0) {
+ rc = cx231xx_set_gpio_value(dev, gpio->bit, gpio->val);
+ if (rc < 0)
+ return rc;
+
+ if (gpio->sleep > 0)
+ msleep(gpio->sleep);
+
+ gpio++;
+ }
+ return rc;
+}
+
+int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
+{
+ if (dev->mode == set_mode)
+ return 0;
+
+ if (set_mode == CX231XX_SUSPEND) {
+ /* Set the chip in power saving mode */
+ dev->mode = set_mode;
+ }
+
+ /* Resource is locked */
+ if (dev->mode != CX231XX_SUSPEND)
+ return -EINVAL;
+
+ dev->mode = set_mode;
+
+ if (dev->mode == CX231XX_DIGITAL_MODE)
+ ;/* Set Digital power mode */
+ else
+ ;/* Set Analog Power mode */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_set_mode);
+
+/*****************************************************************
+* URB Streaming functions *
+******************************************************************/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void cx231xx_irq_callback(struct urb *urb, struct pt_regs *regs)
+#else
+static void cx231xx_irq_callback(struct urb *urb)
+#endif
+{
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ struct cx231xx_video_mode *vmode =
+ container_of(dma_q, struct cx231xx_video_mode, vidq);
+ struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+ int rc, i;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ /* Copy data from URB */
+ spin_lock(&dev->video_mode.slock);
+ rc = dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock(&dev->video_mode.slock);
+
+ /* Reset urb buffers */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ urb->status = 0;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ cx231xx_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
+ }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void cx231xx_uninit_isoc(struct cx231xx *dev)
+{
+ struct urb *urb;
+ int i;
+
+ cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n");
+
+ dev->video_mode.isoc_ctl.nfields = -1;
+ for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
+ urb = dev->video_mode.isoc_ctl.urb[i];
+ if (urb) {
+ if (!irqs_disabled())
+ usb_kill_urb(urb);
+ else
+ usb_unlink_urb(urb);
+
+ if (dev->video_mode.isoc_ctl.transfer_buffer[i]) {
+ usb_buffer_free(dev->udev,
+ urb->transfer_buffer_length,
+ dev->video_mode.isoc_ctl.
+ transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ dev->video_mode.isoc_ctl.urb[i] = NULL;
+ }
+ dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree(dev->video_mode.isoc_ctl.urb);
+ kfree(dev->video_mode.isoc_ctl.transfer_buffer);
+
+ dev->video_mode.isoc_ctl.urb = NULL;
+ dev->video_mode.isoc_ctl.transfer_buffer = NULL;
+ dev->video_mode.isoc_ctl.num_bufs = 0;
+
+ cx231xx_capture_start(dev, 0, Raw_Video);
+}
+EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct cx231xx *dev, struct urb *urb))
+{
+ struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int j, k;
+ int rc;
+
+ cx231xx_isocdbg("cx231xx: called cx231xx_prepare_isoc\n");
+
+ dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+
+ cx231xx_info("Setting Video mux to %d\n", dev->video_input);
+ video_mux(dev, dev->video_input);
+
+ /* De-allocates all pending stuff */
+ cx231xx_uninit_isoc(dev);
+
+ dev->video_mode.isoc_ctl.isoc_copy = isoc_copy;
+ dev->video_mode.isoc_ctl.num_bufs = num_bufs;
+ dma_q->pos = 0;
+ dma_q->is_partial_line = 0;
+ dma_q->last_sav = 0;
+ dma_q->current_field = -1;
+ dma_q->field1_done = 0;
+ dma_q->lines_per_field = dev->height / 2;
+ dma_q->bytes_left_in_line = dev->width << 1;
+ dma_q->lines_completed = 0;
+ for (i = 0; i < 8; i++)
+ dma_q->partial_buf[i] = 0;
+
+ dev->video_mode.isoc_ctl.urb =
+ kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+ if (!dev->video_mode.isoc_ctl.urb) {
+ cx231xx_errdev("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->video_mode.isoc_ctl.transfer_buffer =
+ kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+ if (!dev->video_mode.isoc_ctl.transfer_buffer) {
+ cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+ kfree(dev->video_mode.isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->video_mode.isoc_ctl.max_pkt_size = max_pkt_size;
+ dev->video_mode.isoc_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->video_mode.isoc_ctl.max_pkt_size;
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ cx231xx_err("cannot alloc isoc_ctl.urb %i\n", i);
+ cx231xx_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ dev->video_mode.isoc_ctl.urb[i] = urb;
+
+ dev->video_mode.isoc_ctl.transfer_buffer[i] =
+ usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) {
+ cx231xx_err("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
+ cx231xx_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->video_mode.isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ pipe =
+ usb_rcvisocpipe(dev->udev, dev->video_mode.end_point_addr);
+
+ usb_fill_int_urb(urb, dev->udev, pipe,
+ dev->video_mode.isoc_ctl.transfer_buffer[i],
+ sb_size, cx231xx_irq_callback, dma_q, 1);
+
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP;
+
+ k = 0;
+ for (j = 0; j < max_packets; j++) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ dev->video_mode.isoc_ctl.max_pkt_size;
+ k += dev->video_mode.isoc_ctl.max_pkt_size;
+ }
+ }
+
+ init_waitqueue_head(&dma_q->wq);
+
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->video_mode.isoc_ctl.urb[i],
+ GFP_ATOMIC);
+ if (rc) {
+ cx231xx_err("submit of urb %i failed (error=%i)\n", i,
+ rc);
+ cx231xx_uninit_isoc(dev);
+ return rc;
+ }
+ }
+
+ cx231xx_capture_start(dev, 1, Raw_Video);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_init_isoc);
+
+/*****************************************************************
+* Device Init/UnInit functions *
+******************************************************************/
+int cx231xx_dev_init(struct cx231xx *dev)
+{
+ int errCode = 0;
+
+ /* Initialize I2C bus */
+
+ /* External Master 1 Bus */
+ dev->i2c_bus[0].nr = 0;
+ dev->i2c_bus[0].dev = dev;
+ dev->i2c_bus[0].i2c_period = I2C_SPEED_1M; /* 1MHz */
+ dev->i2c_bus[0].i2c_nostop = 0;
+ dev->i2c_bus[0].i2c_reserve = 0;
+
+ /* External Master 2 Bus */
+ dev->i2c_bus[1].nr = 1;
+ dev->i2c_bus[1].dev = dev;
+ dev->i2c_bus[1].i2c_period = I2C_SPEED_1M; /* 1MHz */
+ dev->i2c_bus[1].i2c_nostop = 0;
+ dev->i2c_bus[1].i2c_reserve = 0;
+
+ /* Internal Master 3 Bus */
+ dev->i2c_bus[2].nr = 2;
+ dev->i2c_bus[2].dev = dev;
+ dev->i2c_bus[2].i2c_period = I2C_SPEED_400K; /* 400kHz */
+ dev->i2c_bus[2].i2c_nostop = 0;
+ dev->i2c_bus[2].i2c_reserve = 0;
+
+ /* register I2C buses */
+ cx231xx_i2c_register(&dev->i2c_bus[0]);
+ cx231xx_i2c_register(&dev->i2c_bus[1]);
+ cx231xx_i2c_register(&dev->i2c_bus[2]);
+
+ /* init hardware */
+ /* Note : with out calling set power mode function,
+ afe can not be set up correctly */
+ errCode = cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: Failed to set Power - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* initialize Colibri block */
+ errCode = cx231xx_afe_init_super_block(dev, 0x23c);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: cx231xx_afe init super block - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+ errCode = cx231xx_afe_init_channels(dev);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: cx231xx_afe init channels - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* Set DIF in By pass mode */
+ errCode = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: cx231xx_dif set to By pass mode - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* I2S block related functions */
+ errCode = cx231xx_i2s_blk_initialize(dev);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: cx231xx_i2s block initialize - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* init control pins */
+ errCode = cx231xx_init_ctrl_pin_status(dev);
+ if (errCode < 0) {
+ cx231xx_errdev("%s: cx231xx_init ctrl pins - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* set AGC mode to Analog */
+ errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: cx231xx_AGC mode to Analog - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+
+ /* set all alternate settings to zero initially */
+ cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+ cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+ if (dev->board.has_dvb)
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+
+ /* set the I2C master port to 3 on channel 1 */
+ errCode = cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+
+ return errCode;
+}
+EXPORT_SYMBOL_GPL(cx231xx_dev_init);
+
+void cx231xx_dev_uninit(struct cx231xx *dev)
+{
+ /* Un Initialize I2C bus */
+ cx231xx_i2c_unregister(&dev->i2c_bus[2]);
+ cx231xx_i2c_unregister(&dev->i2c_bus[1]);
+ cx231xx_i2c_unregister(&dev->i2c_bus[0]);
+}
+EXPORT_SYMBOL_GPL(cx231xx_dev_uninit);
+
+/*****************************************************************
+* G P I O related functions *
+******************************************************************/
+int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val,
+ u8 len, u8 request, u8 direction)
+{
+ int status = 0;
+ struct VENDOR_REQUEST_IN ven_req;
+
+ /* Set wValue */
+ ven_req.wValue = (u16) (gpio_bit >> 16 & 0xffff);
+
+ /* set request */
+ if (!request) {
+ if (direction)
+ ven_req.bRequest = VRT_GET_GPIO; /* 0x8 gpio */
+ else
+ ven_req.bRequest = VRT_SET_GPIO; /* 0x9 gpio */
+ } else {
+ if (direction)
+ ven_req.bRequest = VRT_GET_GPIE; /* 0xa gpie */
+ else
+ ven_req.bRequest = VRT_SET_GPIE; /* 0xb gpie */
+ }
+
+ /* set index value */
+ ven_req.wIndex = (u16) (gpio_bit & 0xffff);
+
+ /* set wLength value */
+ ven_req.wLength = len;
+
+ /* set bData value */
+ ven_req.bData = 0;
+
+ /* set the buffer for read / write */
+ ven_req.pBuff = gpio_val;
+
+ /* set the direction */
+ if (direction) {
+ ven_req.direction = USB_DIR_IN;
+ memset(ven_req.pBuff, 0x00, ven_req.wLength);
+ } else
+ ven_req.direction = USB_DIR_OUT;
+
+#if 0
+ cx231xx_isocdbg("bRequest = %x\n", ven_req.bRequest);
+ cx231xx_isocdbg("wValue = %x\n", ven_req.wValue);
+ cx231xx_isocdbg("wIndex = %x\n", ven_req.wIndex);
+ cx231xx_isocdbg("wLength = %x\n", ven_req.wLength);
+ for (int i = 0; i < ven_req.wLength; i++)
+ cx231xx_isocdbg("pBuff[i] = %x\n", ven_req.pBuff[i]);
+#endif
+
+ /* call common vendor command request */
+ status = cx231xx_send_vendor_cmd(dev, &ven_req);
+ if (status < 0) {
+ cx231xx_info
+ ("UsbInterface::sendCommand, failed with status -%d\n",
+ status);
+ }
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_send_gpio_cmd);
+
+/*****************************************************************
+ * C O N T R O L - Register R E A D / W R I T E functions *
+ *****************************************************************/
+int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
+{
+ u8 value[4] = { 0x0, 0x0, 0x0, 0x0 };
+ u32 tmp = 0;
+ int status = 0;
+
+ status =
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, address, value, 4);
+ if (status < 0)
+ return status;
+
+ tmp = *((u32 *) value);
+ tmp |= mode;
+
+ value[0] = (u8) tmp;
+ value[1] = (u8) (tmp >> 8);
+ value[2] = (u8) (tmp >> 16);
+ value[3] = (u8) (tmp >> 24);
+
+ status =
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, address, value, 4);
+
+ return status;
+}
+
+/*****************************************************************
+ * I 2 C Internal C O N T R O L functions *
+ *****************************************************************/
+int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+ u8 saddr_len, u32 *data, u8 data_len)
+{
+ int status = 0;
+ struct cx231xx_i2c_xfer_data req_data;
+ u8 value[4] = { 0, 0, 0, 0 };
+
+ if (saddr_len == 0)
+ saddr = 0;
+ else if (saddr_len == 0)
+ saddr &= 0xff;
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = dev_addr >> 1;
+ req_data.direction = I2C_M_RD;
+ req_data.saddr_len = saddr_len;
+ req_data.saddr_dat = saddr;
+ req_data.buf_size = data_len;
+ req_data.p_buffer = (u8 *) value;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data);
+
+ if (status >= 0) {
+ /* Copy the data read back to main buffer */
+ if (data_len == 1)
+ *data = value[0];
+ else
+ *data =
+ value[0] | value[1] << 8 | value[2] << 16 | value[3]
+ << 24;
+ }
+
+ return status;
+}
+
+int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+ u8 saddr_len, u32 data, u8 data_len)
+{
+ int status = 0;
+ u8 value[4] = { 0, 0, 0, 0 };
+ struct cx231xx_i2c_xfer_data req_data;
+
+ value[0] = (u8) data;
+ value[1] = (u8) (data >> 8);
+ value[2] = (u8) (data >> 16);
+ value[3] = (u8) (data >> 24);
+
+ if (saddr_len == 0)
+ saddr = 0;
+ else if (saddr_len == 0)
+ saddr &= 0xff;
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = dev_addr >> 1;
+ req_data.direction = 0;
+ req_data.saddr_len = saddr_len;
+ req_data.saddr_dat = saddr;
+ req_data.buf_size = data_len;
+ req_data.p_buffer = value;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data);
+
+ return status;
+}
+
+int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size,
+ u16 register_address, u8 bit_start, u8 bit_end,
+ u32 value)
+{
+ int status = 0;
+ u32 tmp;
+ u32 mask = 0;
+ int i;
+
+ if (bit_start > (size - 1) || bit_end > (size - 1))
+ return -1;
+
+ if (size == 8) {
+ status =
+ cx231xx_read_i2c_data(dev, dev_addr, register_address, 2,
+ &tmp, 1);
+ } else {
+ status =
+ cx231xx_read_i2c_data(dev, dev_addr, register_address, 2,
+ &tmp, 4);
+ }
+
+ if (status < 0)
+ return status;
+
+ mask = 1 << bit_end;
+ for (i = bit_end; i > bit_start && i > 0; i--)
+ mask = mask + (1 << (i - 1));
+
+ value <<= bit_start;
+
+ if (size == 8) {
+ tmp &= ~mask;
+ tmp |= value;
+ tmp &= 0xff;
+ status =
+ cx231xx_write_i2c_data(dev, dev_addr, register_address, 2,
+ tmp, 1);
+ } else {
+ tmp &= ~mask;
+ tmp |= value;
+ status =
+ cx231xx_write_i2c_data(dev, dev_addr, register_address, 2,
+ tmp, 4);
+ }
+
+ return status;
+}
+
+int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr,
+ u16 saddr, u32 mask, u32 value)
+{
+ u32 temp;
+ int status = 0;
+
+ status = cx231xx_read_i2c_data(dev, dev_addr, saddr, 2, &temp, 4);
+
+ if (status < 0)
+ return status;
+
+ temp &= ~mask;
+ temp |= value;
+
+ status = cx231xx_write_i2c_data(dev, dev_addr, saddr, 2, temp, 4);
+
+ return status;
+}
+
+u32 cx231xx_set_field(u32 field_mask, u32 data)
+{
+ u32 temp;
+
+ for (temp = field_mask; (temp & 1) == 0; temp >>= 1)
+ data <<= 1;
+
+ return data;
+}
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-dvb.c b/linux/drivers/media/video/cx231xx/cx231xx-dvb.c
new file mode 100644
index 000000000..9ff097055
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -0,0 +1,560 @@
+/*
+ DVB device driver for cx231xx
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include "compat.h"
+
+#include "cx231xx.h"
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+
+#include "xc5000.h"
+#include "dvb_dummy_fe.h"
+
+MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
+MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level, fmt, arg...) do { \
+if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
+} while (0)
+
+#define CX231XX_DVB_NUM_BUFS 5
+#define CX231XX_DVB_MAX_PACKETSIZE 564
+#define CX231XX_DVB_MAX_PACKETS 64
+
+struct cx231xx_dvb {
+ struct dvb_frontend *frontend;
+
+ /* feed count management */
+ struct mutex lock;
+ int nfeeds;
+
+ /* general boilerplate stuff */
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+};
+
+static inline void print_err_status(struct cx231xx *dev, int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ dprintk(1, "URB status %d [%s].\n", status, errmsg);
+ } else {
+ dprintk(1, "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+ int i;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+
+ return 0;
+}
+
+static int start_streaming(struct cx231xx_dvb *dvb)
+{
+ int rc;
+ struct cx231xx *dev = dvb->adapter.priv;
+
+ usb_set_interface(dev->udev, 0, 1);
+ rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ if (rc < 0)
+ return rc;
+
+ return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
+ CX231XX_DVB_NUM_BUFS,
+ CX231XX_DVB_MAX_PACKETSIZE, dvb_isoc_copy);
+}
+
+static int stop_streaming(struct cx231xx_dvb *dvb)
+{
+ struct cx231xx *dev = dvb->adapter.priv;
+
+ cx231xx_uninit_isoc(dev);
+
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+ return 0;
+}
+
+static int start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx231xx_dvb *dvb = demux->priv;
+ int rc, ret;
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds++;
+ rc = dvb->nfeeds;
+
+ if (dvb->nfeeds == 1) {
+ ret = start_streaming(dvb);
+ if (ret < 0)
+ rc = ret;
+ }
+
+ mutex_unlock(&dvb->lock);
+ return rc;
+}
+
+static int stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx231xx_dvb *dvb = demux->priv;
+ int err = 0;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds--;
+
+ if (0 == dvb->nfeeds)
+ err = stop_streaming(dvb);
+
+ mutex_unlock(&dvb->lock);
+ return err;
+}
+
+/* ------------------------------------------------------------------ */
+static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct cx231xx *dev = fe->dvb->priv;
+
+ if (acquire)
+ return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ else
+ return cx231xx_set_mode(dev, CX231XX_SUSPEND);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct xc5000_config cnxt_rde250_tunerconfig = {
+ .i2c_address = 0x61,
+ .if_khz = 5380,
+};
+
+/* ------------------------------------------------------------------ */
+#if 0 /* Keep */
+static int attach_xc5000(u8 addr, struct cx231xx *dev)
+{
+
+ struct dvb_frontend *fe;
+ struct xc5000_config cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.i2c_adap = &dev->i2c_bus[1].i2c_adap;
+ cfg.i2c_addr = addr;
+
+ if (!dev->dvb->frontend) {
+ printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ "Can't attach xc5000\n", dev->name);
+ return -EINVAL;
+ }
+
+ fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name);
+ dvb_frontend_detach(dev->dvb->frontend);
+ dev->dvb->frontend = NULL;
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name);
+
+ return 0;
+}
+#endif
+
+int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
+{
+ int status = 0;
+
+ if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+
+ struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+
+ if (dops->set_analog_params != NULL) {
+ struct analog_parameters params;
+
+ params.frequency = freq;
+ params.std = dev->norm;
+ params.mode = 0; /* 0- Air; 1 - cable */
+ /*params.audmode = ; */
+
+ /* Set the analog parameters to set the frequency */
+ cx231xx_info("Setting Frequency for XC5000\n");
+ dops->set_analog_params(dev->dvb->frontend, &params);
+ }
+
+ }
+
+ return status;
+}
+
+int cx231xx_reset_analog_tuner(struct cx231xx *dev)
+{
+ int status = 0;
+
+ if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+
+ struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+
+ if (dops->init != NULL && !dev->xc_fw_load_done) {
+
+ cx231xx_info("Reloading firmware for XC5000\n");
+ status = dops->init(dev->dvb->frontend);
+ if (status == 0) {
+ dev->xc_fw_load_done = 1;
+ cx231xx_info
+ ("XC5000 firmware download completed\n");
+ } else {
+ dev->xc_fw_load_done = 0;
+ cx231xx_info
+ ("XC5000 firmware download failed !!!\n");
+ }
+ }
+
+ }
+
+ return status;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int register_dvb(struct cx231xx_dvb *dvb,
+ struct module *module,
+ struct cx231xx *dev, struct device *device)
+{
+ int result;
+
+ mutex_init(&dvb->lock);
+
+ /* register adapter */
+ result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
+ adapter_nr);
+ if (result < 0) {
+ printk(KERN_WARNING
+ "%s: dvb_register_adapter failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_adapter;
+ }
+
+ /* Ensure all frontends negotiate bus access */
+ dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (result < 0) {
+ printk(KERN_WARNING
+ "%s: dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dvb;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = start_feed;
+ dvb->demux.stop_feed = stop_feed;
+
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING
+ "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_WARNING
+ "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING
+ "%s: connect_frontend failed (errno = %d)\n", dev->name,
+ result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+ return result;
+}
+
+static void unregister_dvb(struct cx231xx_dvb *dvb)
+{
+ dvb_net_release(&dvb->net);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+}
+
+static int dvb_init(struct cx231xx *dev)
+{
+ int result = 0;
+ struct cx231xx_dvb *dvb;
+
+ if (!dev->board.has_dvb) {
+ /* This device does not support the extension */
+ return 0;
+ }
+
+ dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);
+
+ if (dvb == NULL) {
+ printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n");
+ return -ENOMEM;
+ }
+ dev->dvb = dvb;
+ dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
+ dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
+
+ cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ /* init frontend */
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_RDE_250:
+
+ /* dev->dvb->frontend = dvb_attach(s5h1411_attach,
+ &dvico_s5h1411_config,
+ &dev->i2c_bus[1].i2c_adap); */
+ dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach dummy front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ if (dvb_attach(xc5000_attach, dev->dvb->frontend,
+ &dev->i2c_bus[1].i2c_adap,
+ &cnxt_rde250_tunerconfig) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ break;
+ case CX231XX_BOARD_CNXT_RDU_250:
+
+ dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach dummy front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ if (dvb_attach(xc5000_attach, dev->dvb->frontend,
+ &dev->i2c_bus[1].i2c_adap,
+ &cnxt_rde250_tunerconfig) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
+ " isn't supported yet\n", dev->name);
+ break;
+ }
+ if (NULL == dvb->frontend) {
+ printk(KERN_ERR
+ "%s/2: frontend initialization failed\n", dev->name);
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* register everything */
+ result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+
+ if (result < 0)
+ goto out_free;
+
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+ printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
+ return 0;
+
+out_free:
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+ kfree(dvb);
+ dev->dvb = NULL;
+ return result;
+}
+
+static int dvb_fini(struct cx231xx *dev)
+{
+ if (!dev->board.has_dvb) {
+ /* This device does not support the extension */
+ return 0;
+ }
+
+ if (dev->dvb) {
+ unregister_dvb(dev->dvb);
+ dev->dvb = NULL;
+ }
+
+ return 0;
+}
+
+static struct cx231xx_ops dvb_ops = {
+ .id = CX231XX_DVB,
+ .name = "Cx231xx dvb Extension",
+ .init = dvb_init,
+ .fini = dvb_fini,
+};
+
+static int __init cx231xx_dvb_register(void)
+{
+ return cx231xx_register_extension(&dvb_ops);
+}
+
+static void __exit cx231xx_dvb_unregister(void)
+{
+ cx231xx_unregister_extension(&dvb_ops);
+}
+
+module_init(cx231xx_dvb_register);
+module_exit(cx231xx_dvb_unregister);
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-i2c.c b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c
new file mode 100644
index 000000000..d196fe666
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c
@@ -0,0 +1,558 @@
+/*
+ cx231xx-i2c.c - driver for Conexant Cx23100/101/102 USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+ Based on Cx23885 driver
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#include "cx231xx.h"
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk1(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(fmt, ##args); \
+ } \
+} while (0)
+
+#define dprintk2(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(KERN_DEBUG "%s at %s: " fmt, \
+ dev->name, __func__ , ##args); \
+ } \
+} while (0)
+
+/*
+ * cx231xx_i2c_send_bytes()
+ */
+int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg)
+{
+ struct cx231xx_i2c *bus = i2c_adap->algo_data;
+ struct cx231xx *dev = bus->dev;
+ struct cx231xx_i2c_xfer_data req_data;
+ int status = 0;
+ u16 size = 0;
+ u8 loop = 0;
+ u8 saddr_len = 1;
+ u8 *buf_ptr = NULL;
+ u16 saddr = 0;
+ u8 need_gpio = 0;
+
+ if ((bus->nr == 1) && (msg->addr == 0x61)
+ && (dev->tuner_type == TUNER_XC5000)) {
+
+ size = msg->len;
+
+ if (size == 2) { /* register write sub addr */
+ /* Just writing sub address will cause problem
+ * to XC5000. So ignore the request */
+ return 0;
+ } else if (size == 4) { /* register write with sub addr */
+ if (msg->len >= 2)
+ saddr = msg->buf[0] << 8 | msg->buf[1];
+ else if (msg->len == 1)
+ saddr = msg->buf[0];
+
+ switch (saddr) {
+ case 0x0000: /* start tuner calibration mode */
+ need_gpio = 1;
+ /* FW Loading is done */
+ dev->xc_fw_load_done = 1;
+ break;
+ case 0x000D: /* Set signal source */
+ case 0x0001: /* Set TV standard - Video */
+ case 0x0002: /* Set TV standard - Audio */
+ case 0x0003: /* Set RF Frequency */
+ need_gpio = 1;
+ break;
+ default:
+ if (dev->xc_fw_load_done)
+ need_gpio = 1;
+ break;
+ }
+
+ if (need_gpio) {
+ dprintk1(1,
+ "GPIO WRITE: addr 0x%x, len %d, saddr 0x%x\n",
+ msg->addr, msg->len, saddr);
+
+ return dev->cx231xx_gpio_i2c_write(dev,
+ msg->addr,
+ msg->buf,
+ msg->len);
+ }
+ }
+
+ /* special case for Xc5000 tuner case */
+ saddr_len = 1;
+
+ /* adjust the length to correct length */
+ size -= saddr_len;
+ buf_ptr = (u8 *) (msg->buf + 1);
+
+ do {
+ /* prepare xfer_data struct */
+ req_data.dev_addr = msg->addr;
+ req_data.direction = msg->flags;
+ req_data.saddr_len = saddr_len;
+ req_data.saddr_dat = msg->buf[0];
+ req_data.buf_size = size > 16 ? 16 : size;
+ req_data.p_buffer = (u8 *) (buf_ptr + loop * 16);
+
+ bus->i2c_nostop = (size > 16) ? 1 : 0;
+ bus->i2c_reserve = (loop == 0) ? 0 : 1;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(bus, &req_data);
+ loop++;
+
+ if (size >= 16)
+ size -= 16;
+ else
+ size = 0;
+
+ } while (size > 0);
+
+ bus->i2c_nostop = 0;
+ bus->i2c_reserve = 0;
+
+ } else { /* regular case */
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = msg->addr;
+ req_data.direction = msg->flags;
+ req_data.saddr_len = 0;
+ req_data.saddr_dat = 0;
+ req_data.buf_size = msg->len;
+ req_data.p_buffer = msg->buf;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(bus, &req_data);
+ }
+
+ return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_recv_bytes()
+ * read a byte from the i2c device
+ */
+static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg)
+{
+ struct cx231xx_i2c *bus = i2c_adap->algo_data;
+ struct cx231xx *dev = bus->dev;
+ struct cx231xx_i2c_xfer_data req_data;
+ int status = 0;
+ u16 saddr = 0;
+ u8 need_gpio = 0;
+
+ if ((bus->nr == 1) && (msg->addr == 0x61)
+ && dev->tuner_type == TUNER_XC5000) {
+
+ if (msg->len == 2)
+ saddr = msg->buf[0] << 8 | msg->buf[1];
+ else if (msg->len == 1)
+ saddr = msg->buf[0];
+
+ if (dev->xc_fw_load_done) {
+
+ switch (saddr) {
+ case 0x0009: /* BUSY check */
+ dprintk1(1,
+ "GPIO R E A D: Special case BUSY check \n");
+ /*Try read BUSY register, just set it to zero*/
+ msg->buf[0] = 0;
+ if (msg->len == 2)
+ msg->buf[1] = 0;
+ return 0;
+ case 0x0004: /* read Lock status */
+ need_gpio = 1;
+ break;
+
+ }
+
+ if (need_gpio) {
+ /* this is a special case to handle Xceive tuner
+ clock stretch issue with gpio based I2C */
+
+ dprintk1(1,
+ "GPIO R E A D: addr 0x%x, len %d, saddr 0x%x\n",
+ msg->addr, msg->len,
+ msg->buf[0] << 8 | msg->buf[1]);
+
+ status =
+ dev->cx231xx_gpio_i2c_write(dev, msg->addr,
+ msg->buf,
+ msg->len);
+ status =
+ dev->cx231xx_gpio_i2c_read(dev, msg->addr,
+ msg->buf,
+ msg->len);
+ return status;
+ }
+ }
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = msg->addr;
+ req_data.direction = msg->flags;
+ req_data.saddr_len = msg->len;
+ req_data.saddr_dat = msg->buf[0] << 8 | msg->buf[1];
+ req_data.buf_size = msg->len;
+ req_data.p_buffer = msg->buf;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(bus, &req_data);
+
+ } else {
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = msg->addr;
+ req_data.direction = msg->flags;
+ req_data.saddr_len = 0;
+ req_data.saddr_dat = 0;
+ req_data.buf_size = msg->len;
+ req_data.p_buffer = msg->buf;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(bus, &req_data);
+ }
+
+ return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_recv_bytes_with_saddr()
+ * read a byte from the i2c device
+ */
+static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg1,
+ const struct i2c_msg *msg2)
+{
+ struct cx231xx_i2c *bus = i2c_adap->algo_data;
+ struct cx231xx *dev = bus->dev;
+ struct cx231xx_i2c_xfer_data req_data;
+ int status = 0;
+ u16 saddr = 0;
+ u8 need_gpio = 0;
+
+ if (msg1->len == 2)
+ saddr = msg1->buf[0] << 8 | msg1->buf[1];
+ else if (msg1->len == 1)
+ saddr = msg1->buf[0];
+
+ if ((bus->nr == 1) && (msg2->addr == 0x61)
+ && dev->tuner_type == TUNER_XC5000) {
+
+ if ((msg2->len < 16)) {
+
+ dprintk1(1,
+ "i2c_read: addr 0x%x, len %d, saddr 0x%x, len %d\n",
+ msg2->addr, msg2->len, saddr, msg1->len);
+
+ switch (saddr) {
+ case 0x0008: /* read FW load status */
+ need_gpio = 1;
+ break;
+ case 0x0004: /* read Lock status */
+ need_gpio = 1;
+ break;
+ }
+
+ if (need_gpio) {
+ status =
+ dev->cx231xx_gpio_i2c_write(dev, msg1->addr,
+ msg1->buf,
+ msg1->len);
+ status =
+ dev->cx231xx_gpio_i2c_read(dev, msg2->addr,
+ msg2->buf,
+ msg2->len);
+ return status;
+ }
+ }
+ }
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = msg2->addr;
+ req_data.direction = msg2->flags;
+ req_data.saddr_len = msg1->len;
+ req_data.saddr_dat = saddr;
+ req_data.buf_size = msg2->len;
+ req_data.p_buffer = msg2->buf;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(bus, &req_data);
+
+ return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg)
+{
+ struct cx231xx_i2c *bus = i2c_adap->algo_data;
+ struct cx231xx *dev = bus->dev;
+ struct cx231xx_i2c_xfer_data req_data;
+ int status = 0;
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = msg->addr;
+ req_data.direction = msg->flags;
+ req_data.saddr_len = 0;
+ req_data.saddr_dat = 0;
+ req_data.buf_size = 0;
+ req_data.p_buffer = NULL;
+
+ /* usb send command */
+ status = dev->cx231xx_send_usb_command(bus, &req_data);
+
+ return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct cx231xx_i2c *bus = i2c_adap->algo_data;
+ struct cx231xx *dev = bus->dev;
+ int addr, rc, i, byte;
+
+ if (num <= 0)
+ return 0;
+
+ for (i = 0; i < num; i++) {
+
+ addr = msgs[i].addr >> 1;
+
+ dprintk2(2, "%s %s addr=%x len=%d:",
+ (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+ i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+ if (!msgs[i].len) {
+ /* no len: check only for device presence */
+ rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]);
+ if (rc < 0) {
+ dprintk2(2, " no device\n");
+ return rc;
+ }
+
+ } else if (msgs[i].flags & I2C_M_RD) {
+ /* read bytes */
+ rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]);
+ if (i2c_debug >= 2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ }
+ } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+ msgs[i].addr == msgs[i + 1].addr
+ && (msgs[i].len <= 2) && (bus->nr < 2)) {
+ /* read bytes */
+ rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
+ &msgs[i],
+ &msgs[i + 1]);
+ if (i2c_debug >= 2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ }
+ i++;
+ } else {
+ /* write bytes */
+ if (i2c_debug >= 2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ }
+ rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]);
+ }
+ if (rc < 0)
+ goto err;
+ if (i2c_debug >= 2)
+ printk("\n");
+ }
+
+ return num;
+err:
+ dprintk2(2, " ERROR: %i\n", rc);
+ return rc;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+/*
+ * attach_inform()
+ * gets called when a device attaches to the i2c bus
+ * does some basic configuration
+ */
+static int attach_inform(struct i2c_client *client)
+{
+ struct cx231xx_i2c *bus = i2c_get_adapdata(client->adapter);
+ struct cx231xx *dev = bus->dev;
+
+ switch (client->addr << 1) {
+ case 0x8e:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ dprintk1(1, "attach_inform: IR detected (%s).\n",
+ ir->phys);
+ cx231xx_set_ir(dev, ir);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct i2c_algorithm cx231xx_algo = {
+ .master_xfer = cx231xx_i2c_xfer,
+ .functionality = functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
+};
+
+static struct i2c_adapter cx231xx_adap_template = {
+ .owner = THIS_MODULE,
+ .name = "cx231xx",
+ .id = I2C_HW_B_CX231XX,
+ .algo = &cx231xx_algo,
+ .client_register = attach_inform,
+};
+
+static struct i2c_client cx231xx_client_template = {
+ .name = "cx231xx internal",
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * i2c_devs
+ * incomplete list of known devices
+ */
+static char *i2c_devs[128] = {
+ [0x60 >> 1] = "colibri",
+ [0x88 >> 1] = "hammerhead",
+ [0x8e >> 1] = "CIR",
+ [0x32 >> 1] = "GeminiIII",
+ [0x02 >> 1] = "Aquarius",
+ [0xa0 >> 1] = "eeprom",
+ [0xc0 >> 1] = "tuner/XC3028",
+ [0xc2 >> 1] = "tuner/XC5000",
+};
+
+/*
+ * cx231xx_do_i2c_scan()
+ * check i2c address range for devices
+ */
+void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ cx231xx_info(": Checking for I2C devices ..\n");
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ cx231xx_info("%s: i2c scan: found device @ 0x%x [%s]\n",
+ dev->name, i << 1,
+ i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+ cx231xx_info(": Completed Checking for I2C devices.\n");
+}
+
+/*
+ * cx231xx_i2c_register()
+ * register i2c bus
+ */
+int cx231xx_i2c_register(struct cx231xx_i2c *bus)
+{
+ struct cx231xx *dev = bus->dev;
+
+ BUG_ON(!dev->cx231xx_send_usb_command);
+
+ memcpy(&bus->i2c_adap, &cx231xx_adap_template, sizeof(bus->i2c_adap));
+ memcpy(&bus->i2c_algo, &cx231xx_algo, sizeof(bus->i2c_algo));
+ memcpy(&bus->i2c_client, &cx231xx_client_template,
+ sizeof(bus->i2c_client));
+
+ bus->i2c_adap.dev.parent = &dev->udev->dev;
+
+ strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name));
+
+ bus->i2c_algo.data = bus;
+ bus->i2c_adap.algo_data = bus;
+ i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
+ i2c_add_adapter(&bus->i2c_adap);
+
+ bus->i2c_client.adapter = &bus->i2c_adap;
+
+ if (0 == bus->i2c_rc) {
+ if (i2c_scan)
+ cx231xx_do_i2c_scan(dev, &bus->i2c_client);
+ } else
+ cx231xx_warn("%s: i2c bus %d register FAILED\n",
+ dev->name, bus->nr);
+
+ return bus->i2c_rc;
+}
+
+/*
+ * cx231xx_i2c_unregister()
+ * unregister i2c_bus
+ */
+int cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
+{
+ i2c_del_adapter(&bus->i2c_adap);
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-input.c b/linux/drivers/media/video/cx231xx/cx231xx-input.c
new file mode 100644
index 000000000..04d954cca
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-input.c
@@ -0,0 +1,263 @@
+/*
+ handle cx231xx IR remotes via linux kernel input layer.
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+
+ < This is a place holder for IR now.>
+
+ 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
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "compat.h"
+#include "cx231xx.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
+
+#define i2cdprintk(fmt, arg...) \
+ if (ir_debug) { \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+ }
+
+#define dprintk(fmt, arg...) \
+ if (ir_debug) { \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+ }
+
+/**********************************************************
+ Polling structure used by cx231xx IR's
+ **********************************************************/
+
+struct cx231xx_ir_poll_result {
+ unsigned int toggle_bit:1;
+ unsigned int read_count:7;
+ u8 rc_address;
+ u8 rc_data[4];
+};
+
+struct cx231xx_IR {
+ struct cx231xx *dev;
+ struct input_dev *input;
+ struct ir_input_state ir;
+ char name[32];
+ char phys[32];
+
+ /* poll external decoder */
+ int polling;
+ struct work_struct work;
+ struct timer_list timer;
+ unsigned int last_toggle:1;
+ unsigned int last_readcount;
+ unsigned int repeat_interval;
+
+ int (*get_key) (struct cx231xx_IR *, struct cx231xx_ir_poll_result *);
+};
+
+/**********************************************************
+ Polling code for cx231xx
+ **********************************************************/
+
+static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
+{
+ int result;
+ int do_sendkey = 0;
+ struct cx231xx_ir_poll_result poll_result;
+
+ /* read the registers containing the IR status */
+ result = ir->get_key(ir, &poll_result);
+ if (result < 0) {
+ dprintk("ir->get_key() failed %d\n", result);
+ return;
+ }
+
+ dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n",
+ poll_result.toggle_bit, poll_result.read_count,
+ ir->last_readcount, poll_result.rc_data[0]);
+
+ if (ir->dev->chip_id == CHIP_ID_EM2874) {
+ /* The em2874 clears the readcount field every time the
+ register is read. The em2860/2880 datasheet says that it
+ is supposed to clear the readcount, but it doesn't. So with
+ the em2874, we are looking for a non-zero read count as
+ opposed to a readcount that is incrementing */
+ ir->last_readcount = 0;
+ }
+
+ if (poll_result.read_count == 0) {
+ /* The button has not been pressed since the last read */
+ } else if (ir->last_toggle != poll_result.toggle_bit) {
+ /* A button has been pressed */
+ dprintk("button has been pressed\n");
+ ir->last_toggle = poll_result.toggle_bit;
+ ir->repeat_interval = 0;
+ do_sendkey = 1;
+ } else if (poll_result.toggle_bit == ir->last_toggle &&
+ poll_result.read_count > 0 &&
+ poll_result.read_count != ir->last_readcount) {
+ /* The button is still being held down */
+ dprintk("button being held down\n");
+
+ /* Debouncer for first keypress */
+ if (ir->repeat_interval++ > 9) {
+ /* Start repeating after 1 second */
+ do_sendkey = 1;
+ }
+ }
+
+ if (do_sendkey) {
+ dprintk("sending keypress\n");
+ ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0],
+ poll_result.rc_data[0]);
+ ir_input_nokey(ir->input, &ir->ir);
+ }
+
+ ir->last_readcount = poll_result.read_count;
+ return;
+}
+
+static void ir_timer(unsigned long data)
+{
+ struct cx231xx_IR *ir = (struct cx231xx_IR *)data;
+
+ schedule_work(&ir->work);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void cx231xx_ir_work(void *data)
+#else
+static void cx231xx_ir_work(struct work_struct *work)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ struct cx231xx_IR *ir = data;
+#else
+ struct cx231xx_IR *ir = container_of(work, struct cx231xx_IR, work);
+#endif
+
+ cx231xx_ir_handle_key(ir);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+}
+
+void cx231xx_ir_start(struct cx231xx_IR *ir)
+{
+ setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&ir->work, cx231xx_ir_work, ir);
+#else
+ INIT_WORK(&ir->work, cx231xx_ir_work);
+#endif
+ schedule_work(&ir->work);
+}
+
+static void cx231xx_ir_stop(struct cx231xx_IR *ir)
+{
+ del_timer_sync(&ir->timer);
+ flush_scheduled_work();
+}
+
+int cx231xx_ir_init(struct cx231xx *dev)
+{
+ struct cx231xx_IR *ir;
+ struct input_dev *input_dev;
+ u8 ir_config;
+ int err = -ENOMEM;
+
+ if (dev->board.ir_codes == NULL) {
+ /* No remote control support */
+ return 0;
+ }
+
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ir || !input_dev)
+ goto err_out_free;
+
+ ir->input = input_dev;
+
+ /* Setup the proper handler based on the chip */
+ switch (dev->chip_id) {
+ default:
+ printk("Unrecognized cx231xx chip id: IR not supported\n");
+ goto err_out_free;
+ }
+
+ /* This is how often we ask the chip for IR information */
+ ir->polling = 100; /* ms */
+
+ /* init input device */
+ snprintf(ir->name, sizeof(ir->name), "cx231xx IR (%s)", dev->name);
+
+ usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+ strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+ ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->board.ir_codes);
+ input_dev->name = ir->name;
+ input_dev->phys = ir->phys;
+ input_dev->id.bustype = BUS_USB;
+ input_dev->id.version = 1;
+ input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ input_dev->dev.parent = &dev->udev->dev;
+#else
+ input_dev->cdev.dev = &dev->udev->dev;
+#endif
+ /* record handles to ourself */
+ ir->dev = dev;
+ dev->ir = ir;
+
+ cx231xx_ir_start(ir);
+
+ /* all done */
+ err = input_register_device(ir->input);
+ if (err)
+ goto err_out_stop;
+
+ return 0;
+err_out_stop:
+ cx231xx_ir_stop(ir);
+ dev->ir = NULL;
+err_out_free:
+ input_free_device(input_dev);
+ kfree(ir);
+ return err;
+}
+
+int cx231xx_ir_fini(struct cx231xx *dev)
+{
+ struct cx231xx_IR *ir = dev->ir;
+
+ /* skip detach on non attached boards */
+ if (!ir)
+ return 0;
+
+ cx231xx_ir_stop(ir);
+ input_unregister_device(ir->input);
+ kfree(ir);
+
+ /* done */
+ dev->ir = NULL;
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c b/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c
new file mode 100644
index 000000000..7473c33e8
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c
@@ -0,0 +1,795 @@
+/*
+ cx231xx-pcb-config.c - driver for Conexant
+ Cx23100/101/102 USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx231xx.h"
+#include "cx231xx-conf-reg.h"
+
+static unsigned int pcb_debug;
+module_param(pcb_debug, int, 0644);
+MODULE_PARM_DESC(pcb_debug, "enable pcb config debug messages [video]");
+
+/******************************************************************************/
+
+struct pcb_config cx231xx_Scenario[] = {
+ {
+ INDEX_SELFPOWER_DIGITAL_ONLY, /* index */
+ USB_SELF_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ MOD_DIGITAL, /* mode */
+ SOURCE_TS_BDA, /* ts1_source, digital tv only */
+ NOT_SUPPORTED, /* ts2_source */
+ NOT_SUPPORTED, /* analog source */
+
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ NOT_SUPPORTED, /* AUDIO */
+ NOT_SUPPORTED, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ ,
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ /* full-speed config */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ NOT_SUPPORTED, /* AUDIO */
+ NOT_SUPPORTED, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+
+ {
+ INDEX_SELFPOWER_DUAL_DIGITAL, /* index */
+ USB_SELF_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ MOD_DIGITAL, /* mode */
+ SOURCE_TS_BDA, /* ts1_source, digital tv only */
+ 0, /* ts2_source,need update from register */
+ NOT_SUPPORTED, /* analog source */
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ 2, /* TS2 index */
+ NOT_SUPPORTED, /* AUDIO */
+ NOT_SUPPORTED, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ /* full-speed */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ 2, /* TS2 index */
+ NOT_SUPPORTED, /* AUDIO */
+ NOT_SUPPORTED, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+
+ {
+ INDEX_SELFPOWER_ANALOG_ONLY, /* index */
+ USB_SELF_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ MOD_ANALOG | MOD_DIF | MOD_EXTERNAL, /* mode ,analog tv only */
+ NOT_SUPPORTED, /* ts1_source, NOT SUPPORT */
+ NOT_SUPPORTED, /* ts2_source,NOT SUPPORT */
+ 0, /* analog source, need update */
+
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ NOT_SUPPORTED, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 1, /* AUDIO */
+ 2, /* VIDEO */
+ 3, /* VANC */
+ 4, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ /* full-speed */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ NOT_SUPPORTED, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 1, /* AUDIO */
+ 2, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+
+ {
+ INDEX_SELFPOWER_DUAL, /* index */
+ USB_SELF_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ /* mode ,analog tv and digital path */
+ MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL,
+ 0, /* ts1_source,will update in register */
+ NOT_SUPPORTED, /* ts2_source,NOT SUPPORT */
+ 0, /* analog source need update */
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 2, /* AUDIO */
+ 3, /* VIDEO */
+ 4, /* VANC */
+ 5, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ /* full-speed */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 2, /* AUDIO */
+ 3, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+
+ {
+ INDEX_SELFPOWER_TRIPLE, /* index */
+ USB_SELF_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ /* mode ,analog tv and digital path */
+ MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL,
+ 0, /* ts1_source, update in register */
+ 0, /* ts2_source,update in register */
+ 0, /* analog source, need update */
+
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ 2, /* TS2 index */
+ 3, /* AUDIO */
+ 4, /* VIDEO */
+ 5, /* VANC */
+ 6, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ /* full-speed */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ 2, /* TS2 index */
+ 3, /* AUDIO */
+ 4, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+
+ {
+ INDEX_SELFPOWER_COMPRESSOR, /* index */
+ USB_SELF_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ /* mode ,analog tv AND DIGITAL path */
+ MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL,
+ NOT_SUPPORTED, /* ts1_source, disable */
+ SOURCE_TS_BDA, /* ts2_source */
+ 0, /* analog source,need update */
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ NOT_SUPPORTED, /* ts1 index */
+ 1, /* TS2 index */
+ 2, /* AUDIO */
+ 3, /* VIDEO */
+ 4, /* VANC */
+ 5, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ /* full-speed */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ NOT_SUPPORTED, /* ts1 index */
+ 1, /* TS2 index */
+ 2, /* AUDIO */
+ 3, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+
+ {
+ INDEX_BUSPOWER_DIGITAL_ONLY, /* index */
+ USB_BUS_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ MOD_DIGITAL, /* mode ,analog tv AND DIGITAL path */
+ SOURCE_TS_BDA, /* ts1_source, disable */
+ NOT_SUPPORTED, /* ts2_source */
+ NOT_SUPPORTED, /* analog source */
+
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index = 2 */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ NOT_SUPPORTED, /* AUDIO */
+ NOT_SUPPORTED, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ /* full-speed */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index = 2 */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ NOT_SUPPORTED, /* AUDIO */
+ NOT_SUPPORTED, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+ {
+ INDEX_BUSPOWER_ANALOG_ONLY, /* index */
+ USB_BUS_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ MOD_ANALOG, /* mode ,analog tv AND DIGITAL path */
+ NOT_SUPPORTED, /* ts1_source, disable */
+ NOT_SUPPORTED, /* ts2_source */
+ SOURCE_ANALOG, /* analog source--analog */
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ NOT_SUPPORTED, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 1, /* AUDIO */
+ 2, /* VIDEO */
+ 3, /* VANC */
+ 4, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ { /* full-speed */
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ NOT_SUPPORTED, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 1, /* AUDIO */
+ 2, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+ {
+ INDEX_BUSPOWER_DIF_ONLY, /* index */
+ USB_BUS_POWER, /* power_type */
+ 0, /* speed , not decide yet */
+ /* mode ,analog tv AND DIGITAL path */
+ MOD_DIF | MOD_ANALOG | MOD_DIGITAL | MOD_EXTERNAL,
+ SOURCE_TS_BDA, /* ts1_source, disable */
+ NOT_SUPPORTED, /* ts2_source */
+ SOURCE_DIF | SOURCE_ANALOG | SOURCE_EXTERNAL, /* analog source, dif */
+ 0, /* digital_index */
+ 0, /* analog index */
+ 0, /* dif_index */
+ 0, /* external_index */
+ 1, /* only one configuration */
+ {
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 2, /* AUDIO */
+ 3, /* VIDEO */
+ 4, /* VANC */
+ 5, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ ,
+ { /* full speed */
+ {
+ 0, /* config index */
+ {
+ 0, /* interrupt ep index */
+ 1, /* ts1 index */
+ NOT_SUPPORTED, /* TS2 index */
+ 2, /* AUDIO */
+ 3, /* VIDEO */
+ NOT_SUPPORTED, /* VANC */
+ NOT_SUPPORTED, /* HANC */
+ NOT_SUPPORTED /* ir_index */
+ }
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ ,
+ {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+ NOT_SUPPORTED}
+ }
+ }
+ }
+ ,
+
+};
+
+/*****************************************************************/
+
+u32 initialize_cx231xx(struct cx231xx *dev)
+{
+ u32 config_info = 0;
+ struct pcb_config *p_pcb_info;
+ u8 usb_speed = 1; /* from register,1--HS, 0--FS */
+ u8 data[4] = { 0, 0, 0, 0 };
+ u32 ts1_source = 0;
+ u32 ts2_source = 0;
+ u32 analog_source = 0;
+ u8 _current_scenario_idx = 0xff;
+
+ ts1_source = SOURCE_TS_BDA;
+ ts2_source = SOURCE_TS_BDA;
+
+ /* read board config register to find out which
+ pcb config it is related to */
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4);
+
+ config_info = *((u32 *) data);
+ usb_speed = (u8) (config_info & 0x1);
+
+ /* Verify this device belongs to Bus power or Self power device */
+ if (config_info & BUS_POWER) { /* bus-power */
+ switch (config_info & BUSPOWER_MASK) {
+ case TS1_PORT | BUS_POWER:
+ cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY].speed =
+ usb_speed;
+ p_pcb_info =
+ &cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY];
+ _current_scenario_idx = INDEX_BUSPOWER_DIGITAL_ONLY;
+ break;
+ case AVDEC_ENABLE | BUS_POWER:
+ cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY].speed =
+ usb_speed;
+ p_pcb_info =
+ &cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY];
+ _current_scenario_idx = INDEX_BUSPOWER_ANALOG_ONLY;
+ break;
+ case AVDEC_ENABLE | BUS_POWER | TS1_PORT:
+ cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY].speed =
+ usb_speed;
+ p_pcb_info = &cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY];
+ _current_scenario_idx = INDEX_BUSPOWER_DIF_ONLY;
+ break;
+ default:
+ cx231xx_info("bad config in buspower!!!!\n");
+ cx231xx_info("config_info=%x\n",
+ (config_info & BUSPOWER_MASK));
+ return 1;
+ }
+ } else { /* self-power */
+
+ switch (config_info & SELFPOWER_MASK) {
+ case TS1_PORT | SELF_POWER:
+ cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY].speed =
+ usb_speed;
+ p_pcb_info =
+ &cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY];
+ _current_scenario_idx = INDEX_SELFPOWER_DIGITAL_ONLY;
+ break;
+ case TS1_TS2_PORT | SELF_POWER:
+ cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL].speed =
+ usb_speed;
+ cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL].
+ ts2_source = ts2_source;
+ p_pcb_info =
+ &cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL];
+ _current_scenario_idx = INDEX_SELFPOWER_DUAL_DIGITAL;
+ break;
+ case AVDEC_ENABLE | SELF_POWER:
+ cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY].speed =
+ usb_speed;
+ cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY].
+ analog_source = analog_source;
+ p_pcb_info =
+ &cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY];
+ _current_scenario_idx = INDEX_SELFPOWER_ANALOG_ONLY;
+ break;
+ case AVDEC_ENABLE | TS1_PORT | SELF_POWER:
+ cx231xx_Scenario[INDEX_SELFPOWER_DUAL].speed =
+ usb_speed;
+ cx231xx_Scenario[INDEX_SELFPOWER_DUAL].ts1_source =
+ ts1_source;
+ cx231xx_Scenario[INDEX_SELFPOWER_DUAL].analog_source =
+ analog_source;
+ p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_DUAL];
+ _current_scenario_idx = INDEX_SELFPOWER_DUAL;
+ break;
+ case AVDEC_ENABLE | TS1_TS2_PORT | SELF_POWER:
+ cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].speed =
+ usb_speed;
+ cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts1_source =
+ ts1_source;
+ cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts2_source =
+ ts2_source;
+ cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].analog_source =
+ analog_source;
+ p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE];
+ _current_scenario_idx = INDEX_SELFPOWER_TRIPLE;
+ break;
+ case AVDEC_ENABLE | TS1VIP_TS2_PORT | SELF_POWER:
+ cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR].speed =
+ usb_speed;
+ cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR].
+ analog_source = analog_source;
+ p_pcb_info =
+ &cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR];
+ _current_scenario_idx = INDEX_SELFPOWER_COMPRESSOR;
+ break;
+ default:
+ cx231xx_info("bad senario!!!!!\n");
+ cx231xx_info("config_info=%x\n",
+ (config_info & SELFPOWER_MASK));
+ return 1;
+ }
+ }
+
+ dev->current_scenario_idx = _current_scenario_idx;
+
+ memcpy(&dev->current_pcb_config, p_pcb_info,
+ sizeof(struct pcb_config));
+
+ if (pcb_debug) {
+ cx231xx_info("SC(0x00) register = 0x%x\n", config_info);
+ cx231xx_info("scenario %d\n",
+ (dev->current_pcb_config.index) + 1);
+ cx231xx_info("type=%x\n", dev->current_pcb_config.type);
+ cx231xx_info("mode=%x\n", dev->current_pcb_config.mode);
+ cx231xx_info("speed=%x\n", dev->current_pcb_config.speed);
+ cx231xx_info("ts1_source=%x\n",
+ dev->current_pcb_config.ts1_source);
+ cx231xx_info("ts2_source=%x\n",
+ dev->current_pcb_config.ts2_source);
+ cx231xx_info("analog_source=%x\n",
+ dev->current_pcb_config.analog_source);
+ }
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h b/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h
new file mode 100644
index 000000000..f5e46e89f
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h
@@ -0,0 +1,231 @@
+/*
+ cx231xx-pcb-cfg.h - driver for Conexant
+ Cx23100/101/102 USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PCB_CONFIG_H_
+#define _PCB_CONFIG_H_
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+/***************************************************************************
+ * Class Information *
+***************************************************************************/
+#define CLASS_DEFAULT 0xFF
+
+enum VENDOR_REQUEST_TYPE {
+ /* Set/Get I2C */
+ VRT_SET_I2C0 = 0x0,
+ VRT_SET_I2C1 = 0x1,
+ VRT_SET_I2C2 = 0x2,
+ VRT_GET_I2C0 = 0x4,
+ VRT_GET_I2C1 = 0x5,
+ VRT_GET_I2C2 = 0x6,
+
+ /* Set/Get GPIO */
+ VRT_SET_GPIO = 0x8,
+ VRT_GET_GPIO = 0x9,
+
+ /* Set/Get GPIE */
+ VRT_SET_GPIE = 0xA,
+ VRT_GET_GPIE = 0xB,
+
+ /* Set/Get Register Control/Status */
+ VRT_SET_REGISTER = 0xC,
+ VRT_GET_REGISTER = 0xD,
+
+ /* Get Extended Compat ID Descriptor */
+ VRT_GET_EXTCID_DESC = 0xFF,
+};
+
+enum BYTE_ENABLE_MASK {
+ ENABLE_ONE_BYTE = 0x1,
+ ENABLE_TWE_BYTE = 0x3,
+ ENABLE_THREE_BYTE = 0x7,
+ ENABLE_FOUR_BYTE = 0xF,
+};
+
+#define SPEED_MASK 0x1
+enum USB_SPEED{
+ FULL_SPEED = 0x0, /* 0: full speed */
+ HIGH_SPEED = 0x1 /* 1: high speed */
+};
+
+enum _true_false{
+ FALSE = 0,
+ TRUE = 1
+};
+
+#define TS_MASK 0x6
+enum TS_PORT{
+ NO_TS_PORT = 0x0, /* 2'b00: Neither port used. PCB not a Hybrid,
+ only offers Analog TV or Video */
+ TS1_PORT = 0x4, /* 2'b10: TS1 Input (Hybrid mode :
+ Digital or External Analog/Compressed source) */
+ TS1_TS2_PORT = 0x6, /* 2'b11: TS1 & TS2 Inputs
+ (Dual inputs from Digital and/or
+ External Analog/Compressed sources) */
+ TS1_EXT_CLOCK = 0x6, /* 2'b11: TS1 & TS2 as selector
+ to external clock */
+ TS1VIP_TS2_PORT = 0x2 /* 2'b01: TS1 used as 656/VIP Output,
+ TS2 Input (from Compressor) */
+};
+
+#define EAVP_MASK 0x8
+enum EAV_PRESENT{
+ NO_EXTERNAL_AV = 0x0, /* 0: No External A/V inputs
+ (no need for i2s blcok),
+ Analog Tuner must be present */
+ EXTERNAL_AV = 0x8 /* 1: External A/V inputs
+ present (requires i2s blk) */
+};
+
+#define ATM_MASK 0x30
+enum AT_MODE{
+ DIF_TUNER = 0x30, /* 2'b11: IF Tuner (requires use of DIF) */
+ BASEBAND_SOUND = 0x20, /* 2'b10: Baseband Composite &
+ Sound-IF Signals present */
+ NO_TUNER = 0x10 /* 2'b0x: No Analog Tuner present */
+};
+
+#define PWR_SEL_MASK 0x40
+enum POWE_TYPE{
+ SELF_POWER = 0x0, /* 0: self power */
+ BUS_POWER = 0x40 /* 1: bus power */
+};
+
+enum USB_POWE_TYPE{
+ USB_SELF_POWER = 0,
+ USB_BUS_POWER
+};
+
+#define BO_0_MASK 0x80
+enum AVDEC_STATUS{
+ AVDEC_DISABLE = 0x0, /* 0: A/V Decoder Disabled */
+ AVDEC_ENABLE = 0x80 /* 1: A/V Decoder Enabled */
+};
+
+#define BO_1_MASK 0x100
+
+#define BUSPOWER_MASK 0xC4 /* for Polaris spec 0.8 */
+#define SELFPOWER_MASK 0x86
+
+/***************************************************************************/
+#define NOT_DECIDE_YET 0xFE
+#define NOT_SUPPORTED 0xFF
+
+/***************************************************************************
+ * for mod field use *
+***************************************************************************/
+#define MOD_DIGITAL 0x1
+#define MOD_ANALOG 0x2
+#define MOD_DIF 0x4
+#define MOD_EXTERNAL 0x8
+#define CAP_ALL_MOD 0x0f
+
+/***************************************************************************
+ * source define *
+***************************************************************************/
+#define SOURCE_DIGITAL 0x1
+#define SOURCE_ANALOG 0x2
+#define SOURCE_DIF 0x4
+#define SOURCE_EXTERNAL 0x8
+#define SOURCE_TS_BDA 0x10
+#define SOURCE_TS_ENCODE 0x20
+#define SOURCE_TS_EXTERNAL 0x40
+
+/***************************************************************************
+ * interface information define *
+***************************************************************************/
+struct INTERFACE_INFO {
+ u8 interrupt_index;
+ u8 ts1_index;
+ u8 ts2_index;
+ u8 audio_index;
+ u8 video_index;
+ u8 vanc_index; /* VBI */
+ u8 hanc_index; /* Sliced CC */
+ u8 ir_index;
+};
+
+enum INDEX_INTERFACE_INFO{
+ INDEX_INTERRUPT = 0x0,
+ INDEX_TS1,
+ INDEX_TS2,
+ INDEX_AUDIO,
+ INDEX_VIDEO,
+ INDEX_VANC,
+ INDEX_HANC,
+ INDEX_IR,
+};
+
+/***************************************************************************
+ * configuration information define *
+***************************************************************************/
+struct CONFIG_INFO {
+ u8 config_index;
+ struct INTERFACE_INFO interface_info;
+};
+
+struct pcb_config {
+ u8 index;
+ u8 type; /* bus power or self power,
+ self power--0, bus_power--1 */
+ u8 speed; /* usb speed, 2.0--1, 1.1--0 */
+ u8 mode; /* digital , anlog, dif or external A/V */
+ u32 ts1_source; /* three source -- BDA,External,encode */
+ u32 ts2_source;
+ u32 analog_source;
+ u8 digital_index; /* bus-power used */
+ u8 analog_index; /* bus-power used */
+ u8 dif_index; /* bus-power used */
+ u8 external_index; /* bus-power used */
+ u8 config_num; /* current config num, 0,1,2,
+ for self-power, always 0 */
+ struct CONFIG_INFO hs_config_info[3];
+ struct CONFIG_INFO fs_config_info[3];
+};
+
+enum INDEX_PCB_CONFIG{
+ INDEX_SELFPOWER_DIGITAL_ONLY = 0x0,
+ INDEX_SELFPOWER_DUAL_DIGITAL,
+ INDEX_SELFPOWER_ANALOG_ONLY,
+ INDEX_SELFPOWER_DUAL,
+ INDEX_SELFPOWER_TRIPLE,
+ INDEX_SELFPOWER_COMPRESSOR,
+ INDEX_BUSPOWER_DIGITAL_ONLY,
+ INDEX_BUSPOWER_ANALOG_ONLY,
+ INDEX_BUSPOWER_DIF_ONLY,
+ INDEX_BUSPOWER_EXTERNAL_ONLY,
+ INDEX_BUSPOWER_EXTERNAL_ANALOG,
+ INDEX_BUSPOWER_EXTERNAL_DIF,
+ INDEX_BUSPOWER_EXTERNAL_DIGITAL,
+ INDEX_BUSPOWER_DIGITAL_ANALOG,
+ INDEX_BUSPOWER_DIGITAL_DIF,
+ INDEX_BUSPOWER_DIGITAL_ANALOG_EXTERNAL,
+ INDEX_BUSPOWER_DIGITAL_DIF_EXTERNAL,
+};
+
+/***************************************************************************/
+struct cx231xx;
+
+u32 initialize_cx231xx(struct cx231xx *p_dev);
+
+#endif
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-reg.h b/linux/drivers/media/video/cx231xx/cx231xx-reg.h
new file mode 100644
index 000000000..750c5d37d
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-reg.h
@@ -0,0 +1,1564 @@
+/*
+ cx231xx-reg.h - driver for Conexant Cx23100/101/102
+ USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX231XX_REG_H
+#define _CX231XX_REG_H
+
+/*****************************************************************************
+ * VBI codes *
+*****************************************************************************/
+
+#define SAV_ACTIVE_VIDEO_FIELD1 0x80
+#define EAV_ACTIVE_VIDEO_FIELD1 0x90
+
+#define SAV_ACTIVE_VIDEO_FIELD2 0xc0
+#define EAV_ACTIVE_VIDEO_FIELD2 0xd0
+
+#define SAV_VBLANK_FIELD1 0xa0
+#define EAV_VBLANK_FIELD1 0xb0
+
+#define SAV_VBLANK_FIELD2 0xe0
+#define EAV_VBLANK_FIELD2 0xf0
+
+#define SAV_VBI_FIELD1 0x20
+#define EAV_VBI_FIELD1 0x30
+
+#define SAV_VBI_FIELD2 0x60
+#define EAV_VBI_FIELD2 0x70
+
+/*****************************************************************************/
+/* Audio ADC Registers */
+#define CH_PWR_CTRL1 0x0000000e
+#define CH_PWR_CTRL2 0x0000000f
+/*****************************************************************************/
+
+#define HOST_REG1 0x000
+#define FLD_FORCE_CHIP_SEL 0x80
+#define FLD_AUTO_INC_DIS 0x20
+#define FLD_PREFETCH_EN 0x10
+/* Reserved [2:3] */
+#define FLD_DIGITAL_PWR_DN 0x02
+#define FLD_SLEEP 0x01
+
+/*****************************************************************************/
+#define HOST_REG2 0x001
+
+/*****************************************************************************/
+#define HOST_REG3 0x002
+
+/*****************************************************************************/
+/* added for polaris */
+#define GPIO_PIN_CTL0 0x3
+#define GPIO_PIN_CTL1 0x4
+#define GPIO_PIN_CTL2 0x5
+#define GPIO_PIN_CTL3 0x6
+#define TS1_PIN_CTL0 0x7
+#define TS1_PIN_CTL1 0x8
+/*****************************************************************************/
+
+#define FLD_CLK_IN_EN 0x80
+#define FLD_XTAL_CTRL 0x70
+#define FLD_BB_CLK_MODE 0x0C
+#define FLD_REF_DIV_PLL 0x02
+#define FLD_REF_SEL_PLL1 0x01
+
+/*****************************************************************************/
+#define CHIP_CTRL 0x100
+/* Reserved [27] */
+/* Reserved [31:21] */
+#define FLD_CHIP_ACFG_DIS 0x00100000
+/* Reserved [19] */
+#define FLD_DUAL_MODE_ADC2 0x00040000
+#define FLD_SIF_EN 0x00020000
+#define FLD_SOFT_RST 0x00010000
+#define FLD_DEVICE_ID 0x0000ffff
+
+/*****************************************************************************/
+#define AFE_CTRL 0x104
+#define AFE_CTRL_C2HH_SRC_CTRL 0x104
+#define FLD_DIF_OUT_SEL 0xc0000000
+#define FLD_AUX_PLL_CLK_ALT_SEL 0x3c000000
+#define FLD_UV_ORDER_MODE 0x02000000
+#define FLD_FUNC_MODE 0x01800000
+#define FLD_ROT1_PHASE_CTL 0x007f8000
+#define FLD_AUD_IN_SEL 0x00004000
+#define FLD_LUMA_IN_SEL 0x00002000
+#define FLD_CHROMA_IN_SEL 0x00001000
+/* reserve [11:10] */
+#define FLD_INV_SPEC_DIS 0x00000200
+#define FLD_VGA_SEL_CH3 0x00000100
+#define FLD_VGA_SEL_CH2 0x00000080
+#define FLD_VGA_SEL_CH1 0x00000040
+#define FLD_DCR_BYP_CH1 0x00000020
+#define FLD_DCR_BYP_CH2 0x00000010
+#define FLD_DCR_BYP_CH3 0x00000008
+#define FLD_EN_12DB_CH3 0x00000004
+#define FLD_EN_12DB_CH2 0x00000002
+#define FLD_EN_12DB_CH1 0x00000001
+
+/* redefine in Cx231xx */
+/*****************************************************************************/
+#define DC_CTRL1 0x108
+/* reserve [31:30] */
+#define FLD_CLAMP_LVL_CH1 0x3fff8000
+#define FLD_CLAMP_LVL_CH2 0x00007fff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define DC_CTRL2 0x10c
+/* reserve [31:28] */
+#define FLD_CLAMP_LVL_CH3 0x00fffe00
+#define FLD_CLAMP_WIND_LENTH 0x000001e0
+#define FLD_C2HH_SAT_MIN 0x0000001e
+#define FLD_FLT_BYP_SEL 0x00000001
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define DC_CTRL3 0x110
+/* reserve [31:16] */
+#define FLD_ERR_GAIN_CTL 0x00070000
+#define FLD_LPF_MIN 0x0000ffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define DC_CTRL4 0x114
+/* reserve [31:31] */
+#define FLD_INTG_CH1 0x7fffffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define DC_CTRL5 0x118
+/* reserve [31:31] */
+#define FLD_INTG_CH2 0x7fffffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define DC_CTRL6 0x11c
+/* reserve [31:31] */
+#define FLD_INTG_CH3 0x7fffffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define PIN_CTRL 0x120
+#define FLD_OEF_AGC_RF 0x00000001
+#define FLD_OEF_AGC_IFVGA 0x00000002
+#define FLD_OEF_AGC_IF 0x00000004
+#define FLD_REG_BO_PUD 0x80000000
+#define FLD_IR_IRQ_STAT 0x40000000
+#define FLD_AUD_IRQ_STAT 0x20000000
+#define FLD_VID_IRQ_STAT 0x10000000
+/* Reserved [27:26] */
+#define FLD_IRQ_N_OUT_EN 0x02000000
+#define FLD_IRQ_N_POLAR 0x01000000
+/* Reserved [23:6] */
+#define FLD_OE_AUX_PLL_CLK 0x00000020
+#define FLD_OE_I2S_BCLK 0x00000010
+#define FLD_OE_I2S_WCLK 0x00000008
+#define FLD_OE_AGC_IF 0x00000004
+#define FLD_OE_AGC_IFVGA 0x00000002
+#define FLD_OE_AGC_RF 0x00000001
+
+/*****************************************************************************/
+#define AUD_IO_CTRL 0x124
+/* Reserved [31:8] */
+#define FLD_I2S_PORT_DIR 0x00000080
+#define FLD_I2S_OUT_SRC 0x00000040
+#define FLD_AUD_CHAN3_SRC 0x00000030
+#define FLD_AUD_CHAN2_SRC 0x0000000c
+#define FLD_AUD_CHAN1_SRC 0x00000003
+
+/*****************************************************************************/
+#define AUD_LOCK1 0x128
+#define FLD_AUD_LOCK_KI_SHIFT 0xc0000000
+#define FLD_AUD_LOCK_KD_SHIFT 0x30000000
+/* Reserved [27:25] */
+#define FLD_EN_AV_LOCK 0x01000000
+#define FLD_VID_COUNT 0x00ffffff
+
+/*****************************************************************************/
+#define AUD_LOCK2 0x12c
+#define FLD_AUD_LOCK_KI_MULT 0xf0000000
+#define FLD_AUD_LOCK_KD_MULT 0x0F000000
+/* Reserved [23:22] */
+#define FLD_AUD_LOCK_FREQ_SHIFT 0x00300000
+#define FLD_AUD_COUNT 0x000fffff
+
+/*****************************************************************************/
+#define AFE_DIAG_CTRL1 0x134
+/* Reserved [31:16] */
+#define FLD_CUV_DLY_LENGTH 0x0000ff00
+#define FLD_YC_DLY_LENGTH 0x000000ff
+
+/*****************************************************************************/
+/* Poalris redefine */
+#define AFE_DIAG_CTRL3 0x138
+/* Reserved [31:26] */
+#define FLD_AUD_DUAL_FLAG_POL 0x02000000
+#define FLD_VID_DUAL_FLAG_POL 0x01000000
+/* Reserved [23:23] */
+#define FLD_COL_CLAMP_DIS_CH1 0x00400000
+#define FLD_COL_CLAMP_DIS_CH2 0x00200000
+#define FLD_COL_CLAMP_DIS_CH3 0x00100000
+
+#define TEST_CTRL1 0x144
+/* Reserved [31:29] */
+#define FLD_LBIST_EN 0x10000000
+/* Reserved [27:10] */
+#define FLD_FI_BIST_INTR_R 0x0000200
+#define FLD_FI_BIST_INTR_L 0x0000100
+#define FLD_BIST_FAIL_AUD_PLL 0x0000080
+#define FLD_BIST_INTR_AUD_PLL 0x0000040
+#define FLD_BIST_FAIL_VID_PLL 0x0000020
+#define FLD_BIST_INTR_VID_PLL 0x0000010
+/* Reserved [3:1] */
+#define FLD_CIR_TEST_DIS 0x00000001
+
+/*****************************************************************************/
+#define TEST_CTRL2 0x148
+#define FLD_TSXCLK_POL_CTL 0x80000000
+#define FLD_ISO_CTL_SEL 0x40000000
+#define FLD_ISO_CTL_EN 0x20000000
+#define FLD_BIST_DEBUGZ 0x10000000
+#define FLD_AUD_BIST_TEST_H 0x0f000000
+/* Reserved [23:22] */
+#define FLD_FLTRN_BIST_TEST_H 0x00020000
+#define FLD_VID_BIST_TEST_H 0x00010000
+/* Reserved [19:17] */
+#define FLD_BIST_TEST_H 0x00010000
+/* Reserved [15:13] */
+#define FLD_TAB_EN 0x00001000
+/* Reserved [11:0] */
+
+/*****************************************************************************/
+#define BIST_STAT 0x14c
+#define FLD_AUD_BIST_FAIL_H 0xfff00000
+#define FLD_FLTRN_BIST_FAIL_H 0x00180000
+#define FLD_VID_BIST_FAIL_H 0x00070000
+#define FLD_AUD_BIST_TST_DONE 0x0000fff0
+#define FLD_FLTRN_BIST_TST_DONE 0x00000008
+#define FLD_VID_BIST_TST_DONE 0x00000007
+
+/*****************************************************************************/
+/* DirectIF registers definition have been moved to DIF_reg.h */
+/*****************************************************************************/
+#define MODE_CTRL 0x400
+#define FLD_AFD_PAL60_DIS 0x20000000
+#define FLD_AFD_FORCE_SECAM 0x10000000
+#define FLD_AFD_FORCE_PALNC 0x08000000
+#define FLD_AFD_FORCE_PAL 0x04000000
+#define FLD_AFD_PALM_SEL 0x03000000
+#define FLD_CKILL_MODE 0x00300000
+#define FLD_COMB_NOTCH_MODE 0x00c00000 /* bit[19:18] */
+#define FLD_CLR_LOCK_STAT 0x00020000
+#define FLD_FAST_LOCK_MD 0x00010000
+#define FLD_WCEN 0x00008000
+#define FLD_CAGCEN 0x00004000
+#define FLD_CKILLEN 0x00002000
+#define FLD_AUTO_SC_LOCK 0x00001000
+#define FLD_MAN_SC_FAST_LOCK 0x00000800
+#define FLD_INPUT_MODE 0x00000600
+#define FLD_AFD_ACQUIRE 0x00000100
+#define FLD_AFD_NTSC_SEL 0x00000080
+#define FLD_AFD_PAL_SEL 0x00000040
+#define FLD_ACFG_DIS 0x00000020
+#define FLD_SQ_PIXEL 0x00000010
+#define FLD_VID_FMT_SEL 0x0000000f
+
+/*****************************************************************************/
+#define OUT_CTRL1 0x404
+#define FLD_POLAR 0x7f000000
+/* Reserved [23] */
+#define FLD_RND_MODE 0x00600000
+#define FLD_VIPCLAMP_EN 0x00100000
+#define FLD_VIPBLANK_EN 0x00080000
+#define FLD_VIP_OPT_AL 0x00040000
+#define FLD_IDID0_SOURCE 0x00020000
+#define FLD_DCMODE 0x00010000
+#define FLD_CLK_GATING 0x0000c000
+#define FLD_CLK_INVERT 0x00002000
+#define FLD_HSFMT 0x00001000
+#define FLD_VALIDFMT 0x00000800
+#define FLD_ACTFMT 0x00000400
+#define FLD_SWAPRAW 0x00000200
+#define FLD_CLAMPRAW_EN 0x00000100
+#define FLD_BLUE_FIELD_EN 0x00000080
+#define FLD_BLUE_FIELD_ACT 0x00000040
+#define FLD_TASKBIT_VAL 0x00000020
+#define FLD_ANC_DATA_EN 0x00000010
+#define FLD_VBIHACTRAW_EN 0x00000008
+#define FLD_MODE10B 0x00000004
+#define FLD_OUT_MODE 0x00000003
+
+/*****************************************************************************/
+#define OUT_CTRL2 0x408
+#define FLD_AUD_GRP 0xc0000000
+#define FLD_SAMPLE_RATE 0x30000000
+#define FLD_AUD_ANC_EN 0x08000000
+#define FLD_EN_C 0x04000000
+#define FLD_EN_B 0x02000000
+#define FLD_EN_A 0x01000000
+/* Reserved [23:20] */
+#define FLD_IDID1_LSB 0x000c0000
+#define FLD_IDID0_LSB 0x00030000
+#define FLD_IDID1_MSB 0x0000ff00
+#define FLD_IDID0_MSB 0x000000ff
+
+/*****************************************************************************/
+#define GEN_STAT 0x40c
+#define FLD_VCR_DETECT 0x00800000
+#define FLD_SPECIAL_PLAY_N 0x00400000
+#define FLD_VPRES 0x00200000
+#define FLD_AGC_LOCK 0x00100000
+#define FLD_CSC_LOCK 0x00080000
+#define FLD_VLOCK 0x00040000
+#define FLD_SRC_LOCK 0x00020000
+#define FLD_HLOCK 0x00010000
+#define FLD_VSYNC_N 0x00008000
+#define FLD_SRC_FIFO_UFLOW 0x00004000
+#define FLD_SRC_FIFO_OFLOW 0x00002000
+#define FLD_FIELD 0x00001000
+#define FLD_AFD_FMT_STAT 0x00000f00
+#define FLD_MV_TYPE2_PAIR 0x00000080
+#define FLD_MV_T3CS 0x00000040
+#define FLD_MV_CS 0x00000020
+#define FLD_MV_PSP 0x00000010
+/* Reserved [3] */
+#define FLD_MV_CDAT 0x00000003
+
+/*****************************************************************************/
+#define INT_STAT_MASK 0x410
+#define FLD_COMB_3D_FIFO_MSK 0x80000000
+#define FLD_WSS_DAT_AVAIL_MSK 0x40000000
+#define FLD_GS2_DAT_AVAIL_MSK 0x20000000
+#define FLD_GS1_DAT_AVAIL_MSK 0x10000000
+#define FLD_CC_DAT_AVAIL_MSK 0x08000000
+#define FLD_VPRES_CHANGE_MSK 0x04000000
+#define FLD_MV_CHANGE_MSK 0x02000000
+#define FLD_END_VBI_EVEN_MSK 0x01000000
+#define FLD_END_VBI_ODD_MSK 0x00800000
+#define FLD_FMT_CHANGE_MSK 0x00400000
+#define FLD_VSYNC_TRAIL_MSK 0x00200000
+#define FLD_HLOCK_CHANGE_MSK 0x00100000
+#define FLD_VLOCK_CHANGE_MSK 0x00080000
+#define FLD_CSC_LOCK_CHANGE_MSK 0x00040000
+#define FLD_SRC_FIFO_UFLOW_MSK 0x00020000
+#define FLD_SRC_FIFO_OFLOW_MSK 0x00010000
+#define FLD_COMB_3D_FIFO_STAT 0x00008000
+#define FLD_WSS_DAT_AVAIL_STAT 0x00004000
+#define FLD_GS2_DAT_AVAIL_STAT 0x00002000
+#define FLD_GS1_DAT_AVAIL_STAT 0x00001000
+#define FLD_CC_DAT_AVAIL_STAT 0x00000800
+#define FLD_VPRES_CHANGE_STAT 0x00000400
+#define FLD_MV_CHANGE_STAT 0x00000200
+#define FLD_END_VBI_EVEN_STAT 0x00000100
+#define FLD_END_VBI_ODD_STAT 0x00000080
+#define FLD_FMT_CHANGE_STAT 0x00000040
+#define FLD_VSYNC_TRAIL_STAT 0x00000020
+#define FLD_HLOCK_CHANGE_STAT 0x00000010
+#define FLD_VLOCK_CHANGE_STAT 0x00000008
+#define FLD_CSC_LOCK_CHANGE_STAT 0x00000004
+#define FLD_SRC_FIFO_UFLOW_STAT 0x00000002
+#define FLD_SRC_FIFO_OFLOW_STAT 0x00000001
+
+/*****************************************************************************/
+#define LUMA_CTRL 0x414
+#define BRIGHTNESS_CTRL_BYTE 0x414
+#define CONTRAST_CTRL_BYTE 0x415
+#define LUMA_CTRL_BYTE_3 0x416
+#define FLD_LUMA_CORE_SEL 0x00c00000
+#define FLD_RANGE 0x00300000
+/* Reserved [19] */
+#define FLD_PEAK_EN 0x00040000
+#define FLD_PEAK_SEL 0x00030000
+#define FLD_CNTRST 0x0000ff00
+#define FLD_BRITE 0x000000ff
+
+/*****************************************************************************/
+#define HSCALE_CTRL 0x418
+#define FLD_HFILT 0x03000000
+#define FLD_HSCALE 0x00ffffff
+
+/*****************************************************************************/
+#define VSCALE_CTRL 0x41c
+#define FLD_LINE_AVG_DIS 0x01000000
+/* Reserved [23:20] */
+#define FLD_VS_INTRLACE 0x00080000
+#define FLD_VFILT 0x00070000
+/* Reserved [15:13] */
+#define FLD_VSCALE 0x00001fff
+
+/*****************************************************************************/
+#define CHROMA_CTRL 0x420
+#define USAT_CTRL_BYTE 0x420
+#define VSAT_CTRL_BYTE 0x421
+#define HUE_CTRL_BYTE 0x422
+#define FLD_C_LPF_EN 0x20000000
+#define FLD_CHR_DELAY 0x1c000000
+#define FLD_C_CORE_SEL 0x03000000
+#define FLD_HUE 0x00ff0000
+#define FLD_VSAT 0x0000ff00
+#define FLD_USAT 0x000000ff
+
+/*****************************************************************************/
+#define VBI_LINE_CTRL1 0x424
+#define FLD_VBI_MD_LINE4 0xff000000
+#define FLD_VBI_MD_LINE3 0x00ff0000
+#define FLD_VBI_MD_LINE2 0x0000ff00
+#define FLD_VBI_MD_LINE1 0x000000ff
+
+/*****************************************************************************/
+#define VBI_LINE_CTRL2 0x428
+#define FLD_VBI_MD_LINE8 0xff000000
+#define FLD_VBI_MD_LINE7 0x00ff0000
+#define FLD_VBI_MD_LINE6 0x0000ff00
+#define FLD_VBI_MD_LINE5 0x000000ff
+
+/*****************************************************************************/
+#define VBI_LINE_CTRL3 0x42c
+#define FLD_VBI_MD_LINE12 0xff000000
+#define FLD_VBI_MD_LINE11 0x00ff0000
+#define FLD_VBI_MD_LINE10 0x0000ff00
+#define FLD_VBI_MD_LINE9 0x000000ff
+
+/*****************************************************************************/
+#define VBI_LINE_CTRL4 0x430
+#define FLD_VBI_MD_LINE16 0xff000000
+#define FLD_VBI_MD_LINE15 0x00ff0000
+#define FLD_VBI_MD_LINE14 0x0000ff00
+#define FLD_VBI_MD_LINE13 0x000000ff
+
+/*****************************************************************************/
+#define VBI_LINE_CTRL5 0x434
+#define FLD_VBI_MD_LINE17 0x000000ff
+
+/*****************************************************************************/
+#define VBI_FC_CFG 0x438
+#define FLD_FC_ALT2 0xff000000
+#define FLD_FC_ALT1 0x00ff0000
+#define FLD_FC_ALT2_TYPE 0x0000f000
+#define FLD_FC_ALT1_TYPE 0x00000f00
+/* Reserved [7:1] */
+#define FLD_FC_SEARCH_MODE 0x00000001
+
+/*****************************************************************************/
+#define VBI_MISC_CFG1 0x43c
+#define FLD_TTX_PKTADRU 0xfff00000
+#define FLD_TTX_PKTADRL 0x000fff00
+/* Reserved [7:6] */
+#define FLD_MOJI_PACK_DIS 0x00000020
+#define FLD_VPS_DEC_DIS 0x00000010
+#define FLD_CRI_MARG_SCALE 0x0000000c
+#define FLD_EDGE_RESYNC_EN 0x00000002
+#define FLD_ADAPT_SLICE_DIS 0x00000001
+
+/*****************************************************************************/
+#define VBI_MISC_CFG2 0x440
+#define FLD_HAMMING_TYPE 0x0f000000
+/* Reserved [23:20] */
+#define FLD_WSS_FIFO_RST 0x00080000
+#define FLD_GS2_FIFO_RST 0x00040000
+#define FLD_GS1_FIFO_RST 0x00020000
+#define FLD_CC_FIFO_RST 0x00010000
+/* Reserved [15:12] */
+#define FLD_VBI3_SDID 0x00000f00
+#define FLD_VBI2_SDID 0x000000f0
+#define FLD_VBI1_SDID 0x0000000f
+
+/*****************************************************************************/
+#define VBI_PAY1 0x444
+#define FLD_GS1_FIFO_DAT 0xFF000000
+#define FLD_GS1_STAT 0x00FF0000
+#define FLD_CC_FIFO_DAT 0x0000FF00
+#define FLD_CC_STAT 0x000000FF
+
+/*****************************************************************************/
+#define VBI_PAY2 0x448
+#define FLD_WSS_FIFO_DAT 0xff000000
+#define FLD_WSS_STAT 0x00ff0000
+#define FLD_GS2_FIFO_DAT 0x0000ff00
+#define FLD_GS2_STAT 0x000000ff
+
+/*****************************************************************************/
+#define VBI_CUST1_CFG1 0x44c
+/* Reserved [31] */
+#define FLD_VBI1_CRIWIN 0x7f000000
+#define FLD_VBI1_SLICE_DIST 0x00f00000
+#define FLD_VBI1_BITINC 0x000fff00
+#define FLD_VBI1_HDELAY 0x000000ff
+
+/*****************************************************************************/
+#define VBI_CUST1_CFG2 0x450
+#define FLD_VBI1_FC_LENGTH 0x1f000000
+#define FLD_VBI1_FRAME_CODE 0x00ffffff
+
+/*****************************************************************************/
+#define VBI_CUST1_CFG3 0x454
+#define FLD_VBI1_HAM_EN 0x80000000
+#define FLD_VBI1_FIFO_MODE 0x70000000
+#define FLD_VBI1_FORMAT_TYPE 0x0f000000
+#define FLD_VBI1_PAYLD_LENGTH 0x00ff0000
+#define FLD_VBI1_CRI_LENGTH 0x0000f000
+#define FLD_VBI1_CRI_MARGIN 0x00000f00
+#define FLD_VBI1_CRI_TIME 0x000000ff
+
+/*****************************************************************************/
+#define VBI_CUST2_CFG1 0x458
+/* Reserved [31] */
+#define FLD_VBI2_CRIWIN 0x7f000000
+#define FLD_VBI2_SLICE_DIST 0x00f00000
+#define FLD_VBI2_BITINC 0x000fff00
+#define FLD_VBI2_HDELAY 0x000000ff
+
+/*****************************************************************************/
+#define VBI_CUST2_CFG2 0x45c
+#define FLD_VBI2_FC_LENGTH 0x1f000000
+#define FLD_VBI2_FRAME_CODE 0x00ffffff
+
+/*****************************************************************************/
+#define VBI_CUST2_CFG3 0x460
+#define FLD_VBI2_HAM_EN 0x80000000
+#define FLD_VBI2_FIFO_MODE 0x70000000
+#define FLD_VBI2_FORMAT_TYPE 0x0f000000
+#define FLD_VBI2_PAYLD_LENGTH 0x00ff0000
+#define FLD_VBI2_CRI_LENGTH 0x0000f000
+#define FLD_VBI2_CRI_MARGIN 0x00000f00
+#define FLD_VBI2_CRI_TIME 0x000000ff
+
+/*****************************************************************************/
+#define VBI_CUST3_CFG1 0x464
+/* Reserved [31] */
+#define FLD_VBI3_CRIWIN 0x7f000000
+#define FLD_VBI3_SLICE_DIST 0x00f00000
+#define FLD_VBI3_BITINC 0x000fff00
+#define FLD_VBI3_HDELAY 0x000000ff
+
+/*****************************************************************************/
+#define VBI_CUST3_CFG2 0x468
+#define FLD_VBI3_FC_LENGTH 0x1f000000
+#define FLD_VBI3_FRAME_CODE 0x00ffffff
+
+/*****************************************************************************/
+#define VBI_CUST3_CFG3 0x46c
+#define FLD_VBI3_HAM_EN 0x80000000
+#define FLD_VBI3_FIFO_MODE 0x70000000
+#define FLD_VBI3_FORMAT_TYPE 0x0f000000
+#define FLD_VBI3_PAYLD_LENGTH 0x00ff0000
+#define FLD_VBI3_CRI_LENGTH 0x0000f000
+#define FLD_VBI3_CRI_MARGIN 0x00000f00
+#define FLD_VBI3_CRI_TIME 0x000000ff
+
+/*****************************************************************************/
+#define HORIZ_TIM_CTRL 0x470
+#define FLD_BGDEL_CNT 0xff000000
+/* Reserved [23:22] */
+#define FLD_HACTIVE_CNT 0x003ff000
+/* Reserved [11:10] */
+#define FLD_HBLANK_CNT 0x000003ff
+
+/*****************************************************************************/
+#define VERT_TIM_CTRL 0x474
+#define FLD_V656BLANK_CNT 0xff000000
+/* Reserved [23:22] */
+#define FLD_VACTIVE_CNT 0x003ff000
+/* Reserved [11:10] */
+#define FLD_VBLANK_CNT 0x000003ff
+
+/*****************************************************************************/
+#define SRC_COMB_CFG 0x478
+#define FLD_CCOMB_2LN_CHECK 0x80000000
+#define FLD_CCOMB_3LN_EN 0x40000000
+#define FLD_CCOMB_2LN_EN 0x20000000
+#define FLD_CCOMB_3D_EN 0x10000000
+/* Reserved [27] */
+#define FLD_LCOMB_3LN_EN 0x04000000
+#define FLD_LCOMB_2LN_EN 0x02000000
+#define FLD_LCOMB_3D_EN 0x01000000
+#define FLD_LUMA_LPF_SEL 0x00c00000
+#define FLD_UV_LPF_SEL 0x00300000
+#define FLD_BLEND_SLOPE 0x000f0000
+#define FLD_CCOMB_REDUCE_EN 0x00008000
+/* Reserved [14:10] */
+#define FLD_SRC_DECIM_RATIO 0x000003ff
+
+/*****************************************************************************/
+#define CHROMA_VBIOFF_CFG 0x47c
+#define FLD_VBI_VOFFSET 0x1f000000
+/* Reserved [23:20] */
+#define FLD_SC_STEP 0x000fffff
+
+/*****************************************************************************/
+#define FIELD_COUNT 0x480
+#define FLD_FIELD_COUNT_FLD 0x000003ff
+
+/*****************************************************************************/
+#define MISC_TIM_CTRL 0x484
+#define FLD_DEBOUNCE_COUNT 0xc0000000
+#define FLD_VT_LINE_CNT_HYST 0x30000000
+/* Reserved [27] */
+#define FLD_AFD_STAT 0x07ff0000
+#define FLD_VPRES_VERT_EN 0x00008000
+/* Reserved [14:12] */
+#define FLD_HR32 0x00000800
+#define FLD_TDALGN 0x00000400
+#define FLD_TDFIELD 0x00000200
+/* Reserved [8:6] */
+#define FLD_TEMPDEC 0x0000003f
+
+/*****************************************************************************/
+#define DFE_CTRL1 0x488
+#define FLD_CLAMP_AUTO_EN 0x80000000
+#define FLD_AGC_AUTO_EN 0x40000000
+#define FLD_VGA_CRUSH_EN 0x20000000
+#define FLD_VGA_AUTO_EN 0x10000000
+#define FLD_VBI_GATE_EN 0x08000000
+#define FLD_CLAMP_LEVEL 0x07000000
+/* Reserved [23:22] */
+#define FLD_CLAMP_SKIP_CNT 0x00300000
+#define FLD_AGC_GAIN 0x000fff00
+/* Reserved [7:6] */
+#define FLD_VGA_GAIN 0x0000003f
+
+/*****************************************************************************/
+#define DFE_CTRL2 0x48c
+#define FLD_VGA_ACQUIRE_RANGE 0x00ff0000
+#define FLD_VGA_TRACK_RANGE 0x0000ff00
+#define FLD_VGA_SYNC 0x000000ff
+
+/*****************************************************************************/
+#define DFE_CTRL3 0x490
+#define FLD_BP_PERCENT 0xff000000
+#define FLD_DFT_THRESHOLD 0x00ff0000
+/* Reserved [15:12] */
+#define FLD_SYNC_WIDTH_SEL 0x00000600
+#define FLD_BP_LOOP_GAIN 0x00000300
+#define FLD_SYNC_LOOP_GAIN 0x000000c0
+/* Reserved [5:4] */
+#define FLD_AGC_LOOP_GAIN 0x0000000c
+#define FLD_DCC_LOOP_GAIN 0x00000003
+
+/*****************************************************************************/
+#define PLL_CTRL 0x494
+#define FLD_PLL_KD 0xff000000
+#define FLD_PLL_KI 0x00ff0000
+#define FLD_PLL_MAX_OFFSET 0x0000ffff
+
+/*****************************************************************************/
+#define HTL_CTRL 0x498
+/* Reserved [31:24] */
+#define FLD_AUTO_LOCK_SPD 0x00080000
+#define FLD_MAN_FAST_LOCK 0x00040000
+#define FLD_HTL_15K_EN 0x00020000
+#define FLD_HTL_500K_EN 0x00010000
+#define FLD_HTL_KD 0x0000ff00
+#define FLD_HTL_KI 0x000000ff
+
+/*****************************************************************************/
+#define COMB_CTRL 0x49c
+#define FLD_COMB_PHASE_LIMIT 0xff000000
+#define FLD_CCOMB_ERR_LIMIT 0x00ff0000
+#define FLD_LUMA_THRESHOLD 0x0000ff00
+#define FLD_LCOMB_ERR_LIMIT 0x000000ff
+
+/*****************************************************************************/
+#define CRUSH_CTRL 0x4a0
+#define FLD_WTW_EN 0x00400000
+#define FLD_CRUSH_FREQ 0x00200000
+#define FLD_MAJ_SEL_EN 0x00100000
+#define FLD_MAJ_SEL 0x000c0000
+/* Reserved [17:15] */
+#define FLD_SYNC_TIP_REDUCE 0x00007e00
+/* Reserved [8:6] */
+#define FLD_SYNC_TIP_INC 0x0000003f
+
+/*****************************************************************************/
+#define SOFT_RST_CTRL 0x4a4
+#define FLD_VD_SOFT_RST 0x00008000
+/* Reserved [14:12] */
+#define FLD_REG_RST_MSK 0x00000800
+#define FLD_VOF_RST_MSK 0x00000400
+#define FLD_MVDET_RST_MSK 0x00000200
+#define FLD_VBI_RST_MSK 0x00000100
+#define FLD_SCALE_RST_MSK 0x00000080
+#define FLD_CHROMA_RST_MSK 0x00000040
+#define FLD_LUMA_RST_MSK 0x00000020
+#define FLD_VTG_RST_MSK 0x00000010
+#define FLD_YCSEP_RST_MSK 0x00000008
+#define FLD_SRC_RST_MSK 0x00000004
+#define FLD_DFE_RST_MSK 0x00000002
+/* Reserved [0] */
+
+/*****************************************************************************/
+#define MV_DT_CTRL1 0x4a8
+/* Reserved [31:29] */
+#define FLD_PSP_STOP_LINE 0x1f000000
+/* Reserved [23:21] */
+#define FLD_PSP_STRT_LINE 0x001f0000
+/* Reserved [15] */
+#define FLD_PSP_LLIMW 0x00007f00
+/* Reserved [7] */
+#define FLD_PSP_ULIMW 0x0000007f
+
+/*****************************************************************************/
+#define MV_DT_CTRL2 0x4aC
+#define FLD_CS_STOPWIN 0xff000000
+#define FLD_CS_STRTWIN 0x00ff0000
+#define FLD_CS_WIDTH 0x0000ff00
+#define FLD_PSP_SPEC_VAL 0x000000ff
+
+/*****************************************************************************/
+#define MV_DT_CTRL3 0x4B0
+#define FLD_AUTO_RATE_DIS 0x80000000
+#define FLD_HLOCK_DIS 0x40000000
+#define FLD_SEL_FIELD_CNT 0x20000000
+#define FLD_CS_TYPE2_SEL 0x10000000
+#define FLD_CS_LINE_THRSH_SEL 0x08000000
+#define FLD_CS_ATHRESH_SEL 0x04000000
+#define FLD_PSP_SPEC_SEL 0x02000000
+#define FLD_PSP_LINES_SEL 0x01000000
+#define FLD_FIELD_CNT 0x00f00000
+#define FLD_CS_TYPE2_CNT 0x000fc000
+#define FLD_CS_LINE_CNT 0x00003f00
+#define FLD_CS_ATHRESH_LEV 0x000000ff
+
+/*****************************************************************************/
+#define CHIP_VERSION 0x4b4
+/* Cx231xx redefine */
+#define VERSION 0x4b4
+#define FLD_REV_ID 0x000000ff
+
+/*****************************************************************************/
+#define MISC_DIAG_CTRL 0x4b8
+/* Reserved [31:24] */
+#define FLD_SC_CONVERGE_THRESH 0x00ff0000
+#define FLD_CCOMB_ERR_LIMIT_3D 0x0000ff00
+#define FLD_LCOMB_ERR_LIMIT_3D 0x000000ff
+
+/*****************************************************************************/
+#define VBI_PASS_CTRL 0x4bc
+#define FLD_VBI_PASS_MD 0x00200000
+#define FLD_VBI_SETUP_DIS 0x00100000
+#define FLD_PASS_LINE_CTRL 0x000fffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define VCR_DET_CTRL 0x4c0
+#define FLD_EN_FIELD_PHASE_DET 0x80000000
+#define FLD_EN_HEAD_SW_DET 0x40000000
+#define FLD_FIELD_PHASE_LENGTH 0x01ff0000
+/* Reserved [29:25] */
+#define FLD_FIELD_PHASE_DELAY 0x0000ff00
+#define FLD_FIELD_PHASE_LIMIT 0x000000f0
+#define FLD_HEAD_SW_DET_LIMIT 0x0000000f
+
+/*****************************************************************************/
+#define DL_CTL 0x800
+#define DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */
+#define DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */
+#define DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */
+#define DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */
+/* Reserved [31:5] */
+#define FLD_START_8051 0x10000000
+#define FLD_DL_ENABLE 0x08000000
+#define FLD_DL_AUTO_INC 0x04000000
+#define FLD_DL_MAP 0x03000000
+
+/*****************************************************************************/
+#define STD_DET_STATUS 0x804
+#define FLD_SPARE_STATUS1 0xff000000
+#define FLD_SPARE_STATUS0 0x00ff0000
+#define FLD_MOD_DET_STATUS1 0x0000ff00
+#define FLD_MOD_DET_STATUS0 0x000000ff
+
+/*****************************************************************************/
+#define AUD_BUILD_NUM 0x806
+#define AUD_VER_NUM 0x807
+#define STD_DET_CTL 0x808
+#define STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */
+#define STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */
+#define FLD_SPARE_CTL0 0xff000000
+#define FLD_DIS_DBX 0x00800000
+#define FLD_DIS_BTSC 0x00400000
+#define FLD_DIS_NICAM_A2 0x00200000
+#define FLD_VIDEO_PRESENT 0x00100000
+#define FLD_DW8051_VIDEO_FORMAT 0x000f0000
+#define FLD_PREF_DEC_MODE 0x0000ff00
+#define FLD_AUD_CONFIG 0x000000ff
+
+/*****************************************************************************/
+#define DW8051_INT 0x80c
+#define FLD_VIDEO_PRESENT_CHANGE 0x80000000
+#define FLD_VIDEO_CHANGE 0x40000000
+#define FLD_RDS_READY 0x20000000
+#define FLD_AC97_INT 0x10000000
+#define FLD_NICAM_BIT_ERROR_TOO_HIGH 0x08000000
+#define FLD_NICAM_LOCK 0x04000000
+#define FLD_NICAM_UNLOCK 0x02000000
+#define FLD_DFT4_TH_CMP 0x01000000
+/* Reserved [23:22] */
+#define FLD_LOCK_IND_INT 0x00200000
+#define FLD_DFT3_TH_CMP 0x00100000
+#define FLD_DFT2_TH_CMP 0x00080000
+#define FLD_DFT1_TH_CMP 0x00040000
+#define FLD_FM2_DFT_TH_CMP 0x00020000
+#define FLD_FM1_DFT_TH_CMP 0x00010000
+#define FLD_VIDEO_PRESENT_EN 0x00008000
+#define FLD_VIDEO_CHANGE_EN 0x00004000
+#define FLD_RDS_READY_EN 0x00002000
+#define FLD_AC97_INT_EN 0x00001000
+#define FLD_NICAM_BIT_ERROR_TOO_HIGH_EN 0x00000800
+#define FLD_NICAM_LOCK_EN 0x00000400
+#define FLD_NICAM_UNLOCK_EN 0x00000200
+#define FLD_DFT4_TH_CMP_EN 0x00000100
+/* Reserved [7] */
+#define FLD_DW8051_INT6_CTL1 0x00000040
+#define FLD_DW8051_INT5_CTL1 0x00000020
+#define FLD_DW8051_INT4_CTL1 0x00000010
+#define FLD_DW8051_INT3_CTL1 0x00000008
+#define FLD_DW8051_INT2_CTL1 0x00000004
+#define FLD_DW8051_INT1_CTL1 0x00000002
+#define FLD_DW8051_INT0_CTL1 0x00000001
+
+/*****************************************************************************/
+#define GENERAL_CTL 0x810
+#define FLD_RDS_INT 0x80000000
+#define FLD_NBER_INT 0x40000000
+#define FLD_NLL_INT 0x20000000
+#define FLD_IFL_INT 0x10000000
+#define FLD_FDL_INT 0x08000000
+#define FLD_AFC_INT 0x04000000
+#define FLD_AMC_INT 0x02000000
+#define FLD_AC97_INT_CTL 0x01000000
+#define FLD_RDS_INT_DIS 0x00800000
+#define FLD_NBER_INT_DIS 0x00400000
+#define FLD_NLL_INT_DIS 0x00200000
+#define FLD_IFL_INT_DIS 0x00100000
+#define FLD_FDL_INT_DIS 0x00080000
+#define FLD_FC_INT_DIS 0x00040000
+#define FLD_AMC_INT_DIS 0x00020000
+#define FLD_AC97_INT_DIS 0x00010000
+#define FLD_REV_NUM 0x0000ff00
+/* Reserved [7:5] */
+#define FLD_DBX_SOFT_RESET_REG 0x00000010
+#define FLD_AD_SOFT_RESET_REG 0x00000008
+#define FLD_SRC_SOFT_RESET_REG 0x00000004
+#define FLD_CDMOD_SOFT_RESET 0x00000002
+#define FLD_8051_SOFT_RESET 0x00000001
+
+/*****************************************************************************/
+#define AAGC_CTL 0x814
+#define FLD_AFE_12DB_EN 0x80000000
+#define FLD_AAGC_DEFAULT_EN 0x40000000
+#define FLD_AAGC_DEFAULT 0x3f000000
+/* Reserved [23] */
+#define FLD_AAGC_GAIN 0x00600000
+#define FLD_AAGC_TH 0x001f0000
+/* Reserved [15:14] */
+#define FLD_AAGC_HYST2 0x00003f00
+/* Reserved [7:6] */
+#define FLD_AAGC_HYST1 0x0000003f
+
+/*****************************************************************************/
+#define IF_SRC_CTL 0x818
+#define FLD_DBX_BYPASS 0x80000000
+/* Reserved [30:25] */
+#define FLD_IF_SRC_MODE 0x01000000
+/* Reserved [23:18] */
+#define FLD_IF_SRC_PHASE_INC 0x0001ffff
+
+/*****************************************************************************/
+#define ANALOG_DEMOD_CTL 0x81c
+#define FLD_ROT1_PHACC_PROG 0xffff0000
+/* Reserved [15] */
+#define FLD_FM1_DELAY_FIX 0x00007000
+#define FLD_PDF4_SHIFT 0x00000c00
+#define FLD_PDF3_SHIFT 0x00000300
+#define FLD_PDF2_SHIFT 0x000000c0
+#define FLD_PDF1_SHIFT 0x00000030
+#define FLD_FMBYPASS_MODE2 0x00000008
+#define FLD_FMBYPASS_MODE1 0x00000004
+#define FLD_NICAM_MODE 0x00000002
+#define FLD_BTSC_FMRADIO_MODE 0x00000001
+
+/*****************************************************************************/
+#define ROT_FREQ_CTL 0x820
+#define FLD_ROT3_PHACC_PROG 0xffff0000
+#define FLD_ROT2_PHACC_PROG 0x0000ffff
+
+/*****************************************************************************/
+#define FM_CTL 0x824
+#define FLD_FM2_DC_FB_SHIFT 0xf0000000
+#define FLD_FM2_DC_INT_SHIFT 0x0f000000
+#define FLD_FM2_AFC_RESET 0x00800000
+#define FLD_FM2_DC_PASS_IN 0x00400000
+#define FLD_FM2_DAGC_SHIFT 0x00380000
+#define FLD_FM2_CORDIC_SHIFT 0x00070000
+#define FLD_FM1_DC_FB_SHIFT 0x0000f000
+#define FLD_FM1_DC_INT_SHIFT 0x00000f00
+#define FLD_FM1_AFC_RESET 0x00000080
+#define FLD_FM1_DC_PASS_IN 0x00000040
+#define FLD_FM1_DAGC_SHIFT 0x00000038
+#define FLD_FM1_CORDIC_SHIFT 0x00000007
+
+/*****************************************************************************/
+#define LPF_PDF_CTL 0x828
+/* Reserved [31:30] */
+#define FLD_LPF32_SHIFT1 0x30000000
+#define FLD_LPF32_SHIFT2 0x0c000000
+#define FLD_LPF160_SHIFTA 0x03000000
+#define FLD_LPF160_SHIFTB 0x00c00000
+#define FLD_LPF160_SHIFTC 0x00300000
+#define FLD_LPF32_COEF_SEL2 0x000c0000
+#define FLD_LPF32_COEF_SEL1 0x00030000
+#define FLD_LPF160_COEF_SELC 0x0000c000
+#define FLD_LPF160_COEF_SELB 0x00003000
+#define FLD_LPF160_COEF_SELA 0x00000c00
+#define FLD_LPF160_IN_EN_REG 0x00000300
+#define FLD_PDF4_PDF_SEL 0x000000c0
+#define FLD_PDF3_PDF_SEL 0x00000030
+#define FLD_PDF2_PDF_SEL 0x0000000c
+#define FLD_PDF1_PDF_SEL 0x00000003
+
+/*****************************************************************************/
+#define DFT1_CTL1 0x82c
+#define FLD_DFT1_DWELL 0xffff0000
+#define FLD_DFT1_FREQ 0x0000ffff
+
+/*****************************************************************************/
+#define DFT1_CTL2 0x830
+#define FLD_DFT1_THRESHOLD 0xffffff00
+#define FLD_DFT1_CMP_CTL 0x00000080
+#define FLD_DFT1_AVG 0x00000070
+/* Reserved [3:1] */
+#define FLD_DFT1_START 0x00000001
+
+/*****************************************************************************/
+#define DFT1_STATUS 0x834
+#define FLD_DFT1_DONE 0x80000000
+#define FLD_DFT1_TH_CMP_STAT 0x40000000
+#define FLD_DFT1_RESULT 0x3fffffff
+
+/*****************************************************************************/
+#define DFT2_CTL1 0x838
+#define FLD_DFT2_DWELL 0xffff0000
+#define FLD_DFT2_FREQ 0x0000ffff
+
+/*****************************************************************************/
+#define DFT2_CTL2 0x83C
+#define FLD_DFT2_THRESHOLD 0xffffff00
+#define FLD_DFT2_CMP_CTL 0x00000080
+#define FLD_DFT2_AVG 0x00000070
+/* Reserved [3:1] */
+#define FLD_DFT2_START 0x00000001
+
+/*****************************************************************************/
+#define DFT2_STATUS 0x840
+#define FLD_DFT2_DONE 0x80000000
+#define FLD_DFT2_TH_CMP_STAT 0x40000000
+#define FLD_DFT2_RESULT 0x3fffffff
+
+/*****************************************************************************/
+#define DFT3_CTL1 0x844
+#define FLD_DFT3_DWELL 0xffff0000
+#define FLD_DFT3_FREQ 0x0000ffff
+
+/*****************************************************************************/
+#define DFT3_CTL2 0x848
+#define FLD_DFT3_THRESHOLD 0xffffff00
+#define FLD_DFT3_CMP_CTL 0x00000080
+#define FLD_DFT3_AVG 0x00000070
+/* Reserved [3:1] */
+#define FLD_DFT3_START 0x00000001
+
+/*****************************************************************************/
+#define DFT3_STATUS 0x84c
+#define FLD_DFT3_DONE 0x80000000
+#define FLD_DFT3_TH_CMP_STAT 0x40000000
+#define FLD_DFT3_RESULT 0x3fffffff
+
+/*****************************************************************************/
+#define DFT4_CTL1 0x850
+#define FLD_DFT4_DWELL 0xffff0000
+#define FLD_DFT4_FREQ 0x0000ffff
+
+/*****************************************************************************/
+#define DFT4_CTL2 0x854
+#define FLD_DFT4_THRESHOLD 0xffffff00
+#define FLD_DFT4_CMP_CTL 0x00000080
+#define FLD_DFT4_AVG 0x00000070
+/* Reserved [3:1] */
+#define FLD_DFT4_START 0x00000001
+
+/*****************************************************************************/
+#define DFT4_STATUS 0x858
+#define FLD_DFT4_DONE 0x80000000
+#define FLD_DFT4_TH_CMP_STAT 0x40000000
+#define FLD_DFT4_RESULT 0x3fffffff
+
+/*****************************************************************************/
+#define AM_MTS_DET 0x85c
+#define FLD_AM_MTS_MODE 0x80000000
+/* Reserved [30:26] */
+#define FLD_AM_SUB 0x02000000
+#define FLD_AM_GAIN_EN 0x01000000
+/* Reserved [23:16] */
+#define FLD_AMMTS_GAIN_SCALE 0x0000e000
+#define FLD_MTS_PDF_SHIFT 0x00001800
+#define FLD_AM_REG_GAIN 0x00000700
+#define FLD_AGC_REF 0x000000ff
+
+/*****************************************************************************/
+#define ANALOG_MUX_CTL 0x860
+/* Reserved [31:29] */
+#define FLD_MUX21_SEL 0x10000000
+#define FLD_MUX20_SEL 0x08000000
+#define FLD_MUX19_SEL 0x04000000
+#define FLD_MUX18_SEL 0x02000000
+#define FLD_MUX17_SEL 0x01000000
+#define FLD_MUX16_SEL 0x00800000
+#define FLD_MUX15_SEL 0x00400000
+#define FLD_MUX14_SEL 0x00300000
+#define FLD_MUX13_SEL 0x000C0000
+#define FLD_MUX12_SEL 0x00020000
+#define FLD_MUX11_SEL 0x00018000
+#define FLD_MUX10_SEL 0x00004000
+#define FLD_MUX9_SEL 0x00002000
+#define FLD_MUX8_SEL 0x00001000
+#define FLD_MUX7_SEL 0x00000800
+#define FLD_MUX6_SEL 0x00000600
+#define FLD_MUX5_SEL 0x00000100
+#define FLD_MUX4_SEL 0x000000c0
+#define FLD_MUX3_SEL 0x00000030
+#define FLD_MUX2_SEL 0x0000000c
+#define FLD_MUX1_SEL 0x00000003
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DPLL_CTRL1 0x864
+#define DIG_PLL_CTL1 0x864
+
+#define FLD_PLL_STATUS 0x07000000
+#define FLD_BANDWIDTH_SELECT 0x00030000
+#define FLD_PLL_SHIFT_REG 0x00007000
+#define FLD_PHASE_SHIFT 0x000007ff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DPLL_CTRL2 0x868
+#define DIG_PLL_CTL2 0x868
+#define FLD_PLL_UNLOCK_THR 0xff000000
+#define FLD_PLL_LOCK_THR 0x00ff0000
+/* Reserved [15:8] */
+#define FLD_AM_PDF_SEL2 0x000000c0
+#define FLD_AM_PDF_SEL1 0x00000030
+#define FLD_DPLL_FSM_CTRL 0x0000000c
+/* Reserved [1] */
+#define FLD_PLL_PILOT_DET 0x00000001
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DPLL_CTRL3 0x86c
+#define DIG_PLL_CTL3 0x86c
+#define FLD_DISABLE_LOOP 0x01000000
+#define FLD_A1_DS1_SEL 0x000c0000
+#define FLD_A1_DS2_SEL 0x00030000
+#define FLD_A1_KI 0x0000ff00
+#define FLD_A1_KD 0x000000ff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DPLL_CTRL4 0x870
+#define DIG_PLL_CTL4 0x870
+#define FLD_A2_DS1_SEL 0x000c0000
+#define FLD_A2_DS2_SEL 0x00030000
+#define FLD_A2_KI 0x0000ff00
+#define FLD_A2_KD 0x000000ff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DPLL_CTRL5 0x874
+#define DIG_PLL_CTL5 0x874
+#define FLD_TRK_DS1_SEL 0x000c0000
+#define FLD_TRK_DS2_SEL 0x00030000
+#define FLD_TRK_KI 0x0000ff00
+#define FLD_TRK_KD 0x000000ff
+
+/*****************************************************************************/
+#define DEEMPH_GAIN_CTL 0x878
+#define FLD_DEEMPH2_GAIN 0xFFFF0000
+#define FLD_DEEMPH1_GAIN 0x0000FFFF
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DEEMPH_COEFF1 0x87c
+#define DEEMPH_COEF1 0x87c
+#define FLD_DEEMPH_B0 0xffff0000
+#define FLD_DEEMPH_A0 0x0000ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DEEMPH_COEFF2 0x880
+#define DEEMPH_COEF2 0x880
+#define FLD_DEEMPH_B1 0xFFFF0000
+#define FLD_DEEMPH_A1 0x0000FFFF
+
+/*****************************************************************************/
+#define DBX1_CTL1 0x884
+#define FLD_DBX1_WBE_GAIN 0xffff0000
+#define FLD_DBX1_IN_GAIN 0x0000ffff
+
+/*****************************************************************************/
+#define DBX1_CTL2 0x888
+#define FLD_DBX1_SE_BYPASS 0xffff0000
+#define FLD_DBX1_SE_GAIN 0x0000ffff
+
+/*****************************************************************************/
+#define DBX1_RMS_SE 0x88C
+#define FLD_DBX1_RMS_WBE 0xffff0000
+#define FLD_DBX1_RMS_SE_FLD 0x0000ffff
+
+/*****************************************************************************/
+#define DBX2_CTL1 0x890
+#define FLD_DBX2_WBE_GAIN 0xffff0000
+#define FLD_DBX2_IN_GAIN 0x0000ffff
+
+/*****************************************************************************/
+#define DBX2_CTL2 0x894
+#define FLD_DBX2_SE_BYPASS 0xffff0000
+#define FLD_DBX2_SE_GAIN 0x0000ffff
+
+/*****************************************************************************/
+#define DBX2_RMS_SE 0x898
+#define FLD_DBX2_RMS_WBE 0xffff0000
+#define FLD_DBX2_RMS_SE_FLD 0x0000ffff
+
+/*****************************************************************************/
+#define AM_FM_DIFF 0x89c
+/* Reserved [31] */
+#define FLD_FM_DIFF_OUT 0x7fff0000
+/* Reserved [15] */
+#define FLD_AM_DIFF_OUT 0x00007fff
+
+/*****************************************************************************/
+#define NICAM_FAW 0x8a0
+#define FLD_FAWDETWINEND 0xFc000000
+#define FLD_FAWDETWINSTR 0x03ff0000
+/* Reserved [15:12] */
+#define FLD_FAWDETTHRSHLD3 0x00000f00
+#define FLD_FAWDETTHRSHLD2 0x000000f0
+#define FLD_FAWDETTHRSHLD1 0x0000000f
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DEEMPH_GAIN 0x8a4
+#define NICAM_DEEMPHGAIN 0x8a4
+/* Reserved [31:18] */
+#define FLD_DEEMPHGAIN 0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DEEMPH_NUMER1 0x8a8
+#define NICAM_DEEMPHNUMER1 0x8a8
+/* Reserved [31:18] */
+#define FLD_DEEMPHNUMER1 0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DEEMPH_NUMER2 0x8ac
+#define NICAM_DEEMPHNUMER2 0x8ac
+/* Reserved [31:18] */
+#define FLD_DEEMPHNUMER2 0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DEEMPH_DENOM1 0x8b0
+#define NICAM_DEEMPHDENOM1 0x8b0
+/* Reserved [31:18] */
+#define FLD_DEEMPHDENOM1 0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define DEEMPH_DENOM2 0x8b4
+#define NICAM_DEEMPHDENOM2 0x8b4
+/* Reserved [31:18] */
+#define FLD_DEEMPHDENOM2 0x0003ffff
+
+/*****************************************************************************/
+#define NICAM_ERRLOG_CTL1 0x8B8
+/* Reserved [31:28] */
+#define FLD_ERRINTRPTTHSHLD1 0x0fff0000
+/* Reserved [15:12] */
+#define FLD_ERRLOGPERIOD 0x00000fff
+
+/*****************************************************************************/
+#define NICAM_ERRLOG_CTL2 0x8bc
+/* Reserved [31:28] */
+#define FLD_ERRINTRPTTHSHLD3 0x0fff0000
+/* Reserved [15:12] */
+#define FLD_ERRINTRPTTHSHLD2 0x00000fff
+
+/*****************************************************************************/
+#define NICAM_ERRLOG_STS1 0x8c0
+/* Reserved [31:28] */
+#define FLD_ERRLOG2 0x0fff0000
+/* Reserved [15:12] */
+#define FLD_ERRLOG1 0x00000fff
+
+/*****************************************************************************/
+#define NICAM_ERRLOG_STS2 0x8c4
+/* Reserved [31:12] */
+#define FLD_ERRLOG3 0x00000fff
+
+/*****************************************************************************/
+#define NICAM_STATUS 0x8c8
+/* Reserved [31:20] */
+#define FLD_NICAM_CIB 0x000c0000
+#define FLD_NICAM_LOCK_STAT 0x00020000
+#define FLD_NICAM_MUTE 0x00010000
+#define FLD_NICAMADDIT_DATA 0x0000ffe0
+#define FLD_NICAMCNTRL 0x0000001f
+
+/*****************************************************************************/
+#define DEMATRIX_CTL 0x8cc
+#define FLD_AC97_IN_SHIFT 0xf0000000
+#define FLD_I2S_IN_SHIFT 0x0f000000
+#define FLD_DEMATRIX_SEL_CTL 0x00ff0000
+/* Reserved [15:11] */
+#define FLD_DMTRX_BYPASS 0x00000400
+#define FLD_DEMATRIX_MODE 0x00000300
+/* Reserved [7:6] */
+#define FLD_PH_DBX_SEL 0x00000020
+#define FLD_PH_CH_SEL 0x00000010
+#define FLD_PHASE_FIX 0x0000000f
+
+/*****************************************************************************/
+#define PATH1_CTL1 0x8d0
+/* Reserved [31:29] */
+#define FLD_PATH1_MUTE_CTL 0x1f000000
+/* Reserved [23:22] */
+#define FLD_PATH1_AVC_CG 0x00300000
+#define FLD_PATH1_AVC_RT 0x000f0000
+#define FLD_PATH1_AVC_AT 0x0000f000
+#define FLD_PATH1_AVC_STEREO 0x00000800
+#define FLD_PATH1_AVC_CR 0x00000700
+#define FLD_PATH1_AVC_RMS_CON 0x000000f0
+#define FLD_PATH1_SEL_CTL 0x0000000f
+
+/*****************************************************************************/
+#define PATH1_VOL_CTL 0x8d4
+#define FLD_PATH1_AVC_THRESHOLD 0x7fff0000
+#define FLD_PATH1_BAL_LEFT 0x00008000
+#define FLD_PATH1_BAL_LEVEL 0x00007f00
+#define FLD_PATH1_VOLUME 0x000000ff
+
+/*****************************************************************************/
+#define PATH1_EQ_CTL 0x8d8
+/* Reserved [31:30] */
+#define FLD_PATH1_EQ_TREBLE_VOL 0x3f000000
+/* Reserved [23:22] */
+#define FLD_PATH1_EQ_MID_VOL 0x003f0000
+/* Reserved [15:14] */
+#define FLD_PATH1_EQ_BASS_VOL 0x00003f00
+/* Reserved [7:1] */
+#define FLD_PATH1_EQ_BAND_SEL 0x00000001
+
+/*****************************************************************************/
+#define PATH1_SC_CTL 0x8dc
+#define FLD_PATH1_SC_THRESHOLD 0x7fff0000
+#define FLD_PATH1_SC_RT 0x0000f000
+#define FLD_PATH1_SC_AT 0x00000f00
+#define FLD_PATH1_SC_STEREO 0x00000080
+#define FLD_PATH1_SC_CR 0x00000070
+#define FLD_PATH1_SC_RMS_CON 0x0000000f
+
+/*****************************************************************************/
+#define PATH2_CTL1 0x8e0
+/* Reserved [31:26] */
+#define FLD_PATH2_MUTE_CTL 0x03000000
+/* Reserved [23:22] */
+#define FLD_PATH2_AVC_CG 0x00300000
+#define FLD_PATH2_AVC_RT 0x000f0000
+#define FLD_PATH2_AVC_AT 0x0000f000
+#define FLD_PATH2_AVC_STEREO 0x00000800
+#define FLD_PATH2_AVC_CR 0x00000700
+#define FLD_PATH2_AVC_RMS_CON 0x000000f0
+#define FLD_PATH2_SEL_CTL 0x0000000f
+
+/*****************************************************************************/
+#define PATH2_VOL_CTL 0x8e4
+#define FLD_PATH2_AVC_THRESHOLD 0xffff0000
+#define FLD_PATH2_BAL_LEFT 0x00008000
+#define FLD_PATH2_BAL_LEVEL 0x00007f00
+#define FLD_PATH2_VOLUME 0x000000ff
+
+/*****************************************************************************/
+#define PATH2_EQ_CTL 0x8e8
+/* Reserved [31:30] */
+#define FLD_PATH2_EQ_TREBLE_VOL 0x3f000000
+/* Reserved [23:22] */
+#define FLD_PATH2_EQ_MID_VOL 0x003f0000
+/* Reserved [15:14] */
+#define FLD_PATH2_EQ_BASS_VOL 0x00003f00
+/* Reserved [7:1] */
+#define FLD_PATH2_EQ_BAND_SEL 0x00000001
+
+/*****************************************************************************/
+#define PATH2_SC_CTL 0x8eC
+#define FLD_PATH2_SC_THRESHOLD 0xffff0000
+#define FLD_PATH2_SC_RT 0x0000f000
+#define FLD_PATH2_SC_AT 0x00000f00
+#define FLD_PATH2_SC_STEREO 0x00000080
+#define FLD_PATH2_SC_CR 0x00000070
+#define FLD_PATH2_SC_RMS_CON 0x0000000f
+
+/*****************************************************************************/
+#define SRC_CTL 0x8f0
+#define FLD_SRC_STATUS 0xffffff00
+#define FLD_FIFO_LF_EN 0x000000fc
+#define FLD_BYPASS_LI 0x00000002
+#define FLD_BYPASS_PF 0x00000001
+
+/*****************************************************************************/
+#define SRC_LF_COEF 0x8f4
+#define FLD_LOOP_FILTER_COEF2 0xffff0000
+#define FLD_LOOP_FILTER_COEF1 0x0000ffff
+
+/*****************************************************************************/
+#define SRC1_CTL 0x8f8
+/* Reserved [31:28] */
+#define FLD_SRC1_FIFO_RD_TH 0x0f000000
+/* Reserved [23:18] */
+#define FLD_SRC1_PHASE_INC 0x0003ffff
+
+/*****************************************************************************/
+#define SRC2_CTL 0x8fc
+/* Reserved [31:28] */
+#define FLD_SRC2_FIFO_RD_TH 0x0f000000
+/* Reserved [23:18] */
+#define FLD_SRC2_PHASE_INC 0x0003ffff
+
+/*****************************************************************************/
+#define SRC3_CTL 0x900
+/* Reserved [31:28] */
+#define FLD_SRC3_FIFO_RD_TH 0x0f000000
+/* Reserved [23:18] */
+#define FLD_SRC3_PHASE_INC 0x0003ffff
+
+/*****************************************************************************/
+#define SRC4_CTL 0x904
+/* Reserved [31:28] */
+#define FLD_SRC4_FIFO_RD_TH 0x0f000000
+/* Reserved [23:18] */
+#define FLD_SRC4_PHASE_INC 0x0003ffff
+
+/*****************************************************************************/
+#define SRC5_CTL 0x908
+/* Reserved [31:28] */
+#define FLD_SRC5_FIFO_RD_TH 0x0f000000
+/* Reserved [23:18] */
+#define FLD_SRC5_PHASE_INC 0x0003ffff
+
+/*****************************************************************************/
+#define SRC6_CTL 0x90c
+/* Reserved [31:28] */
+#define FLD_SRC6_FIFO_RD_TH 0x0f000000
+/* Reserved [23:18] */
+#define FLD_SRC6_PHASE_INC 0x0003ffff
+
+/*****************************************************************************/
+#define BAND_OUT_SEL 0x910
+#define FLD_SRC6_IN_SEL 0xc0000000
+#define FLD_SRC6_CLK_SEL 0x30000000
+#define FLD_SRC5_IN_SEL 0x0c000000
+#define FLD_SRC5_CLK_SEL 0x03000000
+#define FLD_SRC4_IN_SEL 0x00c00000
+#define FLD_SRC4_CLK_SEL 0x00300000
+#define FLD_SRC3_IN_SEL 0x000c0000
+#define FLD_SRC3_CLK_SEL 0x00030000
+#define FLD_BASEBAND_BYPASS_CTL 0x0000ff00
+#define FLD_AC97_SRC_SEL 0x000000c0
+#define FLD_I2S_SRC_SEL 0x00000030
+#define FLD_PARALLEL2_SRC_SEL 0x0000000c
+#define FLD_PARALLEL1_SRC_SEL 0x00000003
+
+/*****************************************************************************/
+#define I2S_IN_CTL 0x914
+/* Reserved [31:11] */
+#define FLD_I2S_UP2X_BW20K 0x00000400
+#define FLD_I2S_UP2X_BYPASS 0x00000200
+#define FLD_I2S_IN_MASTER_MODE 0x00000100
+#define FLD_I2S_IN_SONY_MODE 0x00000080
+#define FLD_I2S_IN_RIGHT_JUST 0x00000040
+#define FLD_I2S_IN_WS_SEL 0x00000020
+#define FLD_I2S_IN_BCN_DEL 0x0000001f
+
+/*****************************************************************************/
+#define I2S_OUT_CTL 0x918
+/* Reserved [31:17] */
+#define FLD_I2S_OUT_SOFT_RESET_EN 0x00010000
+/* Reserved [15:9] */
+#define FLD_I2S_OUT_MASTER_MODE 0x00000100
+#define FLD_I2S_OUT_SONY_MODE 0x00000080
+#define FLD_I2S_OUT_RIGHT_JUST 0x00000040
+#define FLD_I2S_OUT_WS_SEL 0x00000020
+#define FLD_I2S_OUT_BCN_DEL 0x0000001f
+
+/*****************************************************************************/
+#define AC97_CTL 0x91c
+/* Reserved [31:26] */
+#define FLD_AC97_UP2X_BW20K 0x02000000
+#define FLD_AC97_UP2X_BYPASS 0x01000000
+/* Reserved [23:17] */
+#define FLD_AC97_RST_ACL 0x00010000
+/* Reserved [15:9] */
+#define FLD_AC97_WAKE_UP_SYNC 0x00000100
+/* Reserved [7:1] */
+#define FLD_AC97_SHUTDOWN 0x00000001
+
+/* Cx231xx redefine */
+#define QPSK_IAGC_CTL1 0x94c
+#define QPSK_IAGC_CTL2 0x950
+#define QPSK_FEPR_FREQ 0x954
+#define QPSK_BTL_CTL1 0x958
+#define QPSK_BTL_CTL2 0x95c
+#define QPSK_CTL_CTL1 0x960
+#define QPSK_CTL_CTL2 0x964
+#define QPSK_MF_FAGC_CTL 0x968
+#define QPSK_EQ_CTL 0x96c
+#define QPSK_LOCK_CTL 0x970
+
+/*****************************************************************************/
+#define FM1_DFT_CTL 0x9a8
+#define FLD_FM1_DFT_THRESHOLD 0xffff0000
+/* Reserved [15:8] */
+#define FLD_FM1_DFT_CMP_CTL 0x00000080
+#define FLD_FM1_DFT_AVG 0x00000070
+/* Reserved [3:1] */
+#define FLD_FM1_DFT_START 0x00000001
+
+/*****************************************************************************/
+#define FM1_DFT_STATUS 0x9ac
+#define FLD_FM1_DFT_DONE 0x80000000
+/* Reserved [30:19] */
+#define FLD_FM_DFT_TH_CMP 0x00040000
+#define FLD_FM1_DFT 0x0003ffff
+
+/*****************************************************************************/
+#define FM2_DFT_CTL 0x9b0
+#define FLD_FM2_DFT_THRESHOLD 0xffff0000
+/* Reserved [15:8] */
+#define FLD_FM2_DFT_CMP_CTL 0x00000080
+#define FLD_FM2_DFT_AVG 0x00000070
+/* Reserved [3:1] */
+#define FLD_FM2_DFT_START 0x00000001
+
+/*****************************************************************************/
+#define FM2_DFT_STATUS 0x9b4
+#define FLD_FM2_DFT_DONE 0x80000000
+/* Reserved [30:19] */
+#define FLD_FM2_DFT_TH_CMP_STAT 0x00040000
+#define FLD_FM2_DFT 0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define AAGC_STATUS_REG 0x9b8
+#define AAGC_STATUS 0x9b8
+/* Reserved [31:27] */
+#define FLD_FM2_DAGC_OUT 0x07000000
+/* Reserved [23:19] */
+#define FLD_FM1_DAGC_OUT 0x00070000
+/* Reserved [15:6] */
+#define FLD_AFE_VGA_OUT 0x0000003f
+
+/*****************************************************************************/
+#define MTS_GAIN_STATUS 0x9bc
+/* Reserved [31:14] */
+#define FLD_MTS_GAIN 0x00003fff
+
+#define RDS_OUT 0x9c0
+#define FLD_RDS_Q 0xffff0000
+#define FLD_RDS_I 0x0000ffff
+
+/*****************************************************************************/
+#define AUTOCONFIG_REG 0x9c4
+/* Reserved [31:4] */
+#define FLD_AUTOCONFIG_MODE 0x0000000f
+
+#define FM_AFC 0x9c8
+#define FLD_FM2_AFC 0xffff0000
+#define FLD_FM1_AFC 0x0000ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define NEW_SPARE 0x9cc
+#define NEW_SPARE_REG 0x9cc
+
+/*****************************************************************************/
+#define DBX_ADJ 0x9d0
+/* Reserved [31:28] */
+#define FLD_DBX2_ADJ 0x0fff0000
+/* Reserved [15:12] */
+#define FLD_DBX1_ADJ 0x00000fff
+
+#define VID_FMT_AUTO 0
+#define VID_FMT_NTSC_M 1
+#define VID_FMT_NTSC_J 2
+#define VID_FMT_NTSC_443 3
+#define VID_FMT_PAL_BDGHI 4
+#define VID_FMT_PAL_M 5
+#define VID_FMT_PAL_N 6
+#define VID_FMT_PAL_NC 7
+#define VID_FMT_PAL_60 8
+#define VID_FMT_SECAM 12
+#define VID_FMT_SECAM_60 13
+
+#define INPUT_MODE_CVBS_0 0 /* INPUT_MODE_VALUE(0) */
+#define INPUT_MODE_YC_1 1 /* INPUT_MODE_VALUE(1) */
+#define INPUT_MODE_YC2_2 2 /* INPUT_MODE_VALUE(2) */
+#define INPUT_MODE_YUV_3 3 /* INPUT_MODE_VALUE(3) */
+
+#define LUMA_LPF_LOW_BANDPASS 0 /* 0.6Mhz LPF BW */
+#define LUMA_LPF_MEDIUM_BANDPASS 1 /* 1.0Mhz LPF BW */
+#define LUMA_LPF_HIGH_BANDPASS 2 /* 1.5Mhz LPF BW */
+
+#define UV_LPF_LOW_BANDPASS 0 /* 0.6Mhz LPF BW */
+#define UV_LPF_MEDIUM_BANDPASS 1 /* 1.0Mhz LPF BW */
+#define UV_LPF_HIGH_BANDPASS 2 /* 1.5Mhz LPF BW */
+
+#define TWO_TAP_FILT 0
+#define THREE_TAP_FILT 1
+#define FOUR_TAP_FILT 2
+#define FIVE_TAP_FILT 3
+
+#define AUD_CHAN_SRC_PARALLEL 0
+#define AUD_CHAN_SRC_I2S_INPUT 1
+#define AUD_CHAN_SRC_FLATIRON 2
+#define AUD_CHAN_SRC_PARALLEL3 3
+
+#define OUT_MODE_601 0
+#define OUT_MODE_656 1
+#define OUT_MODE_VIP11 2
+#define OUT_MODE_VIP20 3
+
+#define PHASE_INC_49MHZ 0x0df22
+#define PHASE_INC_56MHZ 0x0fa5b
+#define PHASE_INC_28MHZ 0x010000
+
+#endif
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-vbi.c b/linux/drivers/media/video/cx231xx/cx231xx-vbi.c
new file mode 100644
index 000000000..020aa13b8
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-vbi.c
@@ -0,0 +1,711 @@
+/*
+ cx231xx_vbi.c - driver for Conexant Cx23100/101/102 USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on cx88 driver
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/msp3400.h>
+#include <media/tuner.h>
+
+#include "cx231xx.h"
+#include "cx231xx-vbi.h"
+
+static inline void print_err_status(struct cx231xx *dev, int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ cx231xx_err(DRIVER_NAME "URB status %d [%s].\n", status,
+ errmsg);
+ } else {
+ cx231xx_err(DRIVER_NAME "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
+{
+ struct cx231xx_buffer *buf;
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ int rc = 1;
+ unsigned char *p_buffer;
+ u32 bytes_parsed = 0, buffer_size = 0;
+ u8 sav_eav = 0;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->vbi_mode.isoc_ctl.buf;
+
+ /* get buffer pointer and length */
+ p_buffer = urb->transfer_buffer;
+ buffer_size = urb->actual_length;
+
+ if (buffer_size > 0) {
+ bytes_parsed = 0;
+
+ if (dma_q->is_partial_line) {
+ /* Handle the case where we were working on a partial
+ line */
+ sav_eav = dma_q->last_sav;
+ } else {
+ /* Check for a SAV/EAV overlapping the
+ buffer boundary */
+
+ sav_eav = cx231xx_find_boundary_SAV_EAV(p_buffer,
+ dma_q->partial_buf,
+ &bytes_parsed);
+ }
+
+ sav_eav &= 0xF0;
+ /* Get the first line if we have some portion of an SAV/EAV from
+ the last buffer or a partial line */
+ if (sav_eav) {
+ bytes_parsed += cx231xx_get_vbi_line(dev, dma_q,
+ sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed); /* buffer size */
+ }
+
+ /* Now parse data that is completely in this buffer */
+ dma_q->is_partial_line = 0;
+
+ while (bytes_parsed < buffer_size) {
+ u32 bytes_used = 0;
+
+ sav_eav = cx231xx_find_next_SAV_EAV(
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed, /* buffer size */
+ &bytes_used); /* bytes used to get SAV/EAV */
+
+ bytes_parsed += bytes_used;
+
+ sav_eav &= 0xF0;
+ if (sav_eav && (bytes_parsed < buffer_size)) {
+ bytes_parsed += cx231xx_get_vbi_line(dev,
+ dma_q, sav_eav, /* SAV/EAV */
+ p_buffer+bytes_parsed, /* p_buffer */
+ buffer_size-bytes_parsed);/*buf size*/
+ }
+ }
+
+ /* Save the last four bytes of the buffer so we can
+ check the buffer boundary condition next time */
+ memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+ bytes_parsed = 0;
+ }
+
+ return rc;
+}
+
+/* ------------------------------------------------------------------
+ Vbi buf operations
+ ------------------------------------------------------------------*/
+
+static int
+vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ u32 height = 0;
+
+ height = ((dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES);
+
+ *size = (dev->width * height * 2);
+ if (0 == *count)
+ *count = CX231XX_DEF_VBI_BUF;
+
+ if (*count < CX231XX_MIN_BUF)
+ *count = CX231XX_MIN_BUF;
+
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->vbi_mode.slock, flags);
+ if (dev->vbi_mode.isoc_ctl.buf == buf)
+ dev->vbi_mode.isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+ u32 height = 0;
+
+ height = ((dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES);
+ buf->vb.size = ((dev->width << 1) * height);
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = height;
+ buf->vb.field = field;
+ buf->vb.field = V4L2_FIELD_SEQ_TB;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (!dev->vbi_mode.isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS,
+ CX231XX_NUM_VBI_BUFS,
+ dev->vbi_mode.alt_max_pkt_size[0],
+ cx231xx_isoc_vbi_copy);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+vbi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void vbi_buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+
+#if 0
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = (struct cx231xx *)fh->dev;
+
+ cx231xx_info(DRIVER_NAME "cx231xx: called vbi_buffer_release\n");
+#endif
+
+ free_buffer(vq, buf);
+}
+
+struct videobuf_queue_ops cx231xx_vbi_qops = {
+ .buf_setup = vbi_buffer_setup,
+ .buf_prepare = vbi_buffer_prepare,
+ .buf_queue = vbi_buffer_queue,
+ .buf_release = vbi_buffer_release,
+};
+
+/* ------------------------------------------------------------------
+ URB control
+ ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void cx231xx_irq_vbi_callback(struct urb *urb, struct pt_regs *regs)
+#else
+static void cx231xx_irq_vbi_callback(struct urb *urb)
+#endif
+{
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ struct cx231xx_video_mode *vmode =
+ container_of(dma_q, struct cx231xx_video_mode, vidq);
+ struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
+ int rc;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ cx231xx_err(DRIVER_NAME "urb completition error %d.\n",
+ urb->status);
+ break;
+ }
+
+ /* Copy data from URB */
+ spin_lock(&dev->vbi_mode.slock);
+ rc = dev->vbi_mode.isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock(&dev->vbi_mode.slock);
+
+ /* Reset status */
+ urb->status = 0;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ cx231xx_err(DRIVER_NAME "urb resubmit failed (error=%i)\n",
+ urb->status);
+ }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
+{
+ struct urb *urb;
+ int i;
+
+ cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n");
+
+ dev->vbi_mode.isoc_ctl.nfields = -1;
+ for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
+ urb = dev->vbi_mode.isoc_ctl.urb[i];
+ if (urb) {
+ if (!irqs_disabled())
+ usb_kill_urb(urb);
+ else
+ usb_unlink_urb(urb);
+
+ if (dev->vbi_mode.isoc_ctl.transfer_buffer[i]) {
+
+ kfree(dev->vbi_mode.isoc_ctl.
+ transfer_buffer[i]);
+ dev->vbi_mode.isoc_ctl.transfer_buffer[i] =
+ NULL;
+ }
+ usb_free_urb(urb);
+ dev->vbi_mode.isoc_ctl.urb[i] = NULL;
+ }
+ dev->vbi_mode.isoc_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree(dev->vbi_mode.isoc_ctl.urb);
+ kfree(dev->vbi_mode.isoc_ctl.transfer_buffer);
+
+ dev->vbi_mode.isoc_ctl.urb = NULL;
+ dev->vbi_mode.isoc_ctl.transfer_buffer = NULL;
+ dev->vbi_mode.isoc_ctl.num_bufs = 0;
+
+ cx231xx_capture_start(dev, 0, Vbi);
+}
+EXPORT_SYMBOL_GPL(cx231xx_uninit_vbi_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct cx231xx *dev,
+ struct urb *urb))
+{
+ struct cx231xx_dmaqueue *dma_q = &dev->vbi_mode.vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int rc;
+
+ cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_prepare_isoc\n");
+
+ /* De-allocates all pending stuff */
+ cx231xx_uninit_vbi_isoc(dev);
+
+ /* clear if any halt */
+ usb_clear_halt(dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->vbi_mode.end_point_addr));
+
+ dev->vbi_mode.isoc_ctl.isoc_copy = isoc_copy;
+ dev->vbi_mode.isoc_ctl.num_bufs = num_bufs;
+ dma_q->pos = 0;
+ dma_q->is_partial_line = 0;
+ dma_q->last_sav = 0;
+ dma_q->current_field = -1;
+ dma_q->bytes_left_in_line = dev->width << 1;
+ dma_q->lines_per_field = ((dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES);
+ dma_q->lines_completed = 0;
+ for (i = 0; i < 8; i++)
+ dma_q->partial_buf[i] = 0;
+
+ dev->vbi_mode.isoc_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
+ GFP_KERNEL);
+ if (!dev->vbi_mode.isoc_ctl.urb) {
+ cx231xx_errdev("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->vbi_mode.isoc_ctl.transfer_buffer =
+ kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+ if (!dev->vbi_mode.isoc_ctl.transfer_buffer) {
+ cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+ kfree(dev->vbi_mode.isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->vbi_mode.isoc_ctl.max_pkt_size = max_pkt_size;
+ dev->vbi_mode.isoc_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->vbi_mode.isoc_ctl.max_pkt_size;
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ cx231xx_err(DRIVER_NAME
+ ": cannot alloc isoc_ctl.urb %i\n", i);
+ cx231xx_uninit_vbi_isoc(dev);
+ return -ENOMEM;
+ }
+ dev->vbi_mode.isoc_ctl.urb[i] = urb;
+ urb->transfer_flags = 0;
+
+ dev->vbi_mode.isoc_ctl.transfer_buffer[i] =
+ kzalloc(sb_size, GFP_KERNEL);
+ if (!dev->vbi_mode.isoc_ctl.transfer_buffer[i]) {
+ cx231xx_err(DRIVER_NAME
+ ": unable to allocate %i bytes for transfer"
+ " buffer %i%s\n", sb_size, i,
+ in_interrupt() ? " while in int" : "");
+ cx231xx_uninit_vbi_isoc(dev);
+ return -ENOMEM;
+ }
+
+ pipe = usb_rcvbulkpipe(dev->udev, dev->vbi_mode.end_point_addr);
+ usb_fill_bulk_urb(urb, dev->udev, pipe,
+ dev->vbi_mode.isoc_ctl.transfer_buffer[i],
+ sb_size, cx231xx_irq_vbi_callback, dma_q);
+ }
+
+ init_waitqueue_head(&dma_q->wq);
+
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->vbi_mode.isoc_ctl.urb[i], GFP_ATOMIC);
+ if (rc) {
+ cx231xx_err(DRIVER_NAME
+ ": submit of urb %i failed (error=%i)\n", i,
+ rc);
+ cx231xx_uninit_vbi_isoc(dev);
+ return rc;
+ }
+ }
+
+ cx231xx_capture_start(dev, 1, Vbi);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_init_vbi_isoc);
+
+u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 sav_eav, u8 *p_buffer, u32 buffer_size)
+{
+ u32 bytes_copied = 0;
+ int current_field = -1;
+
+ switch (sav_eav) {
+
+ case SAV_VBI_FIELD1:
+ current_field = 1;
+ break;
+
+ case SAV_VBI_FIELD2:
+ current_field = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (current_field < 0)
+ return bytes_copied;
+
+ dma_q->last_sav = sav_eav;
+
+ bytes_copied =
+ cx231xx_copy_vbi_line(dev, dma_q, p_buffer, buffer_size,
+ current_field);
+
+ return bytes_copied;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void vbi_buffer_filled(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q,
+ struct cx231xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ /* cx231xx_info(DRIVER_NAME "[%p/%d] wakeup\n", buf, buf->vb.i); */
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->vbi_mode.isoc_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_line, u32 length, int field_number)
+{
+ u32 bytes_to_copy;
+ struct cx231xx_buffer *buf;
+ u32 _line_size = dev->width * 2;
+
+ if (dma_q->current_field != field_number)
+ cx231xx_reset_vbi_buffer(dev, dma_q);
+
+ /* get the buffer pointer */
+ buf = dev->vbi_mode.isoc_ctl.buf;
+
+ /* Remember the field number for next time */
+ dma_q->current_field = field_number;
+
+ bytes_to_copy = dma_q->bytes_left_in_line;
+ if (bytes_to_copy > length)
+ bytes_to_copy = length;
+
+ if (dma_q->lines_completed >= dma_q->lines_per_field) {
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+ dma_q->is_partial_line =
+ (dma_q->bytes_left_in_line == 0) ? 0 : 1;
+ return 0;
+ }
+
+ dma_q->is_partial_line = 1;
+
+ /* If we don't have a buffer, just return the number of bytes we would
+ have copied if we had a buffer. */
+ if (!buf) {
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+ dma_q->is_partial_line =
+ (dma_q->bytes_left_in_line == 0) ? 0 : 1;
+ return bytes_to_copy;
+ }
+
+ /* copy the data to video buffer */
+ cx231xx_do_vbi_copy(dev, dma_q, p_line, bytes_to_copy);
+
+ dma_q->pos += bytes_to_copy;
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+
+ if (dma_q->bytes_left_in_line == 0) {
+
+ dma_q->bytes_left_in_line = _line_size;
+ dma_q->lines_completed++;
+ dma_q->is_partial_line = 0;
+
+ if (cx231xx_is_vbi_buffer_done(dev, dma_q) && buf) {
+
+ vbi_buffer_filled(dev, dma_q, buf);
+
+ dma_q->pos = 0;
+ buf = NULL;
+ dma_q->lines_completed = 0;
+ }
+ }
+
+ return bytes_to_copy;
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
+ struct cx231xx_buffer **buf)
+{
+ struct cx231xx_video_mode *vmode =
+ container_of(dma_q, struct cx231xx_video_mode, vidq);
+ struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ cx231xx_err(DRIVER_NAME ": No active queue to serve\n");
+ dev->vbi_mode.isoc_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue);
+
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+
+ dev->vbi_mode.isoc_ctl.buf = *buf;
+
+ return;
+}
+
+void cx231xx_reset_vbi_buffer(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ struct cx231xx_buffer *buf;
+
+ buf = dev->vbi_mode.isoc_ctl.buf;
+
+ if (buf == NULL) {
+ /* first try to get the buffer */
+ get_next_vbi_buf(dma_q, &buf);
+
+ dma_q->pos = 0;
+ dma_q->current_field = -1;
+ }
+
+ dma_q->bytes_left_in_line = dev->width << 1;
+ dma_q->lines_completed = 0;
+}
+
+int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_buffer, u32 bytes_to_copy)
+{
+ u8 *p_out_buffer = NULL;
+ u32 current_line_bytes_copied = 0;
+ struct cx231xx_buffer *buf;
+ u32 _line_size = dev->width << 1;
+ void *startwrite;
+ int offset, lencopy;
+
+ buf = dev->vbi_mode.isoc_ctl.buf;
+
+ if (buf == NULL)
+ return -EINVAL;
+
+ p_out_buffer = videobuf_to_vmalloc(&buf->vb);
+
+ if (dma_q->bytes_left_in_line != _line_size) {
+ current_line_bytes_copied =
+ _line_size - dma_q->bytes_left_in_line;
+ }
+
+ offset = (dma_q->lines_completed * _line_size) +
+ current_line_bytes_copied;
+
+ /* prepare destination address */
+ startwrite = p_out_buffer + offset;
+
+ lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
+ bytes_to_copy : dma_q->bytes_left_in_line;
+
+ memcpy(startwrite, p_buffer, lencopy);
+
+ return 0;
+}
+
+u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ u32 height = 0;
+
+ height = ((dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES);
+ return (dma_q->lines_completed == height) ? 1 : 0;
+}
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-vbi.h b/linux/drivers/media/video/cx231xx/cx231xx-vbi.h
new file mode 100644
index 000000000..89c7fe80b
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-vbi.h
@@ -0,0 +1,65 @@
+/*
+ cx231xx_vbi.h - driver for Conexant Cx23100/101/102 USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on cx88 driver
+
+ 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.
+ */
+
+#ifndef _CX231XX_VBI_H
+#define _CX231XX_VBI_H
+
+extern struct videobuf_queue_ops cx231xx_vbi_qops;
+
+#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */
+#define NTSC_VBI_END_LINE 21
+#define NTSC_VBI_LINES (NTSC_VBI_END_LINE-NTSC_VBI_START_LINE+1)
+
+#define PAL_VBI_START_LINE 6
+#define PAL_VBI_END_LINE 23
+#define PAL_VBI_LINES (PAL_VBI_END_LINE-PAL_VBI_START_LINE+1)
+
+#define VBI_STRIDE 1440
+#define VBI_SAMPLES_PER_LINE 1440
+
+#define CX231XX_NUM_VBI_PACKETS 4
+#define CX231XX_NUM_VBI_BUFS 5
+
+/* stream functions */
+int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct cx231xx *dev,
+ struct urb *urb));
+
+void cx231xx_uninit_vbi_isoc(struct cx231xx *dev);
+
+/* vbi data copy functions */
+u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 sav_eav, u8 *p_buffer, u32 buffer_size);
+
+u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_line, u32 length, int field_number);
+
+void cx231xx_reset_vbi_buffer(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q);
+
+int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_buffer, u32 bytes_to_copy);
+
+u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q);
+
+#endif
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-video.c b/linux/drivers/media/video/cx231xx/cx231xx-video.c
new file mode 100644
index 000000000..d53ddcb6a
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx-video.c
@@ -0,0 +1,2439 @@
+/*
+ cx231xx-video.c - driver for Conexant Cx23100/101/102
+ USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+ Based on cx23885 driver
+ Based on cx88 driver
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/msp3400.h>
+#include <media/tuner.h>
+
+#include "dvb_frontend.h"
+
+#include "cx231xx.h"
+#include "cx231xx-vbi.h"
+
+#define CX231XX_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+
+#define DRIVER_AUTHOR "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
+#define DRIVER_DESC "Conexant cx231xx based USB video device driver"
+
+#define cx231xx_videodbg(fmt, arg...) do {\
+ if (video_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define cx231xx_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); \
+ } \
+ } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card, int, NULL, 0444);
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(card, "card type");
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+/* supported video standards */
+static struct cx231xx_fmt format[] = {
+ {
+ .name = "16bpp YUY2, 4:2:2, packed",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .reg = 0,
+ },
+};
+
+/* supported controls */
+/* Common to all boards */
+
+/* ------------------------------------------------------------------- */
+
+static const struct v4l2_queryctrl no_ctl = {
+ .name = "42",
+ .flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+static struct cx231xx_ctrl cx231xx_ctls[] = {
+ /* --- video --- */
+ {
+ .v = {
+ .id = V4L2_CID_BRIGHTNESS,
+ .name = "Brightness",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x7f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 128,
+ .reg = LUMA_CTRL,
+ .mask = 0x00ff,
+ .shift = 0,
+ }, {
+ .v = {
+ .id = V4L2_CID_CONTRAST,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x3f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 0,
+ .reg = LUMA_CTRL,
+ .mask = 0xff00,
+ .shift = 8,
+ }, {
+ .v = {
+ .id = V4L2_CID_HUE,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x7f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 128,
+ .reg = CHROMA_CTRL,
+ .mask = 0xff0000,
+ .shift = 16,
+ }, {
+ /* strictly, this only describes only U saturation.
+ * V saturation is handled specially through code.
+ */
+ .v = {
+ .id = V4L2_CID_SATURATION,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x7f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 0,
+ .reg = CHROMA_CTRL,
+ .mask = 0x00ff,
+ .shift = 0,
+ }, {
+ /* --- audio --- */
+ .v = {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },
+ .reg = PATH1_CTL1,
+ .mask = (0x1f << 24),
+ .shift = 24,
+ }, {
+ .v = {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 0x3f,
+ .step = 1,
+ .default_value = 0x3f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .reg = PATH1_VOL_CTL,
+ .mask = 0xff,
+ .shift = 0,
+ }
+};
+static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls);
+
+static const u32 cx231xx_user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+#if 0 /* Keep */
+ V4L2_CID_AUDIO_BALANCE,
+#endif
+ V4L2_CID_AUDIO_MUTE,
+ 0
+};
+
+static const u32 *ctrl_classes[] = {
+ cx231xx_user_ctrls,
+ NULL
+};
+
+/* ------------------------------------------------------------------
+ Video buffer and parser functions
+ ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q,
+ struct cx231xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->video_mode.isoc_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+static inline void print_err_status(struct cx231xx *dev, int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ cx231xx_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
+ struct cx231xx_buffer **buf)
+{
+ struct cx231xx_video_mode *vmode =
+ container_of(dma_q, struct cx231xx_video_mode, vidq);
+ struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ cx231xx_isocdbg("No active queue to serve\n");
+ dev->video_mode.isoc_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue);
+
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+
+ dev->video_mode.isoc_ctl.buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+ struct cx231xx_buffer *buf;
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ unsigned char *outp = NULL;
+ int i, rc = 1;
+ unsigned char *p_buffer;
+ u32 bytes_parsed = 0, buffer_size = 0;
+ u8 sav_eav = 0;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->video_mode.isoc_ctl.buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* cx231xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->video_mode.max_pkt_size) {
+ cx231xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ /* get buffer pointer and length */
+ p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ buffer_size = urb->iso_frame_desc[i].actual_length;
+ bytes_parsed = 0;
+
+ if (dma_q->is_partial_line) {
+ /* Handle the case of a partial line */
+ sav_eav = dma_q->last_sav;
+ } else {
+ /* Check for a SAV/EAV overlapping
+ the buffer boundary */
+ sav_eav =
+ cx231xx_find_boundary_SAV_EAV(p_buffer,
+ dma_q->partial_buf,
+ &bytes_parsed);
+ }
+
+ sav_eav &= 0xF0;
+ /* Get the first line if we have some portion of an SAV/EAV from
+ the last buffer or a partial line */
+ if (sav_eav) {
+ bytes_parsed += cx231xx_get_video_line(dev, dma_q,
+ sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed);/* buf size */
+ }
+
+ /* Now parse data that is completely in this buffer */
+ /* dma_q->is_partial_line = 0; */
+
+ while (bytes_parsed < buffer_size) {
+ u32 bytes_used = 0;
+
+ sav_eav = cx231xx_find_next_SAV_EAV(
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed, /* buf size */
+ &bytes_used);/* bytes used to get SAV/EAV */
+
+ bytes_parsed += bytes_used;
+
+ sav_eav &= 0xF0;
+ if (sav_eav && (bytes_parsed < buffer_size)) {
+ bytes_parsed += cx231xx_get_video_line(dev,
+ dma_q, sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed,/* p_buffer */
+ buffer_size - bytes_parsed);/*buf size*/
+ }
+ }
+
+ /* Save the last four bytes of the buffer so we can check the
+ buffer boundary condition next time */
+ memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+ bytes_parsed = 0;
+
+ }
+ return rc;
+}
+
+u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
+ u32 *p_bytes_used)
+{
+ u32 bytes_used;
+ u8 boundary_bytes[8];
+ u8 sav_eav = 0;
+
+ *p_bytes_used = 0;
+
+ /* Create an array of the last 4 bytes of the last buffer and the first
+ 4 bytes of the current buffer. */
+
+ memcpy(boundary_bytes, partial_buf, 4);
+ memcpy(boundary_bytes + 4, p_buffer, 4);
+
+ /* Check for the SAV/EAV in the boundary buffer */
+ sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8,
+ &bytes_used);
+
+ if (sav_eav) {
+ /* found a boundary SAV/EAV. Updates the bytes used to reflect
+ only those used in the new buffer */
+ *p_bytes_used = bytes_used - 4;
+ }
+
+ return sav_eav;
+}
+
+u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used)
+{
+ u32 i;
+ u8 sav_eav = 0;
+
+ /*
+ * Don't search if the buffer size is less than 4. It causes a page
+ * fault since buffer_size - 4 evaluates to a large number in that
+ * case.
+ */
+ if (buffer_size < 4) {
+ *p_bytes_used = buffer_size;
+ return 0;
+ }
+
+ for (i = 0; i < (buffer_size - 3); i++) {
+
+ if ((p_buffer[i] == 0xFF) &&
+ (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) {
+
+ *p_bytes_used = i + 4;
+ sav_eav = p_buffer[i + 3];
+ return sav_eav;
+ }
+ }
+
+ *p_bytes_used = buffer_size;
+ return 0;
+}
+
+u32 cx231xx_get_video_line(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q, u8 sav_eav,
+ u8 *p_buffer, u32 buffer_size)
+{
+ u32 bytes_copied = 0;
+ int current_field = -1;
+
+ switch (sav_eav) {
+ case SAV_ACTIVE_VIDEO_FIELD1:
+ /* looking for skipped line which occurred in PAL 720x480 mode.
+ In this case, there will be no active data contained
+ between the SAV and EAV */
+ if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
+ (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
+ ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
+ (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD1) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD2)))
+ return bytes_copied;
+ current_field = 1;
+ break;
+
+ case SAV_ACTIVE_VIDEO_FIELD2:
+ /* looking for skipped line which occurred in PAL 720x480 mode.
+ In this case, there will be no active data contained between
+ the SAV and EAV */
+ if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
+ (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
+ ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
+ (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD1) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD2)))
+ return bytes_copied;
+ current_field = 2;
+ break;
+ }
+
+ dma_q->last_sav = sav_eav;
+
+ bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer,
+ buffer_size, current_field);
+
+ return bytes_copied;
+}
+
+u32 cx231xx_copy_video_line(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q, u8 *p_line,
+ u32 length, int field_number)
+{
+ u32 bytes_to_copy;
+ struct cx231xx_buffer *buf;
+ u32 _line_size = dev->width * 2;
+
+ if (dma_q->current_field != field_number)
+ cx231xx_reset_video_buffer(dev, dma_q);
+
+ /* get the buffer pointer */
+ buf = dev->video_mode.isoc_ctl.buf;
+
+ /* Remember the field number for next time */
+ dma_q->current_field = field_number;
+
+ bytes_to_copy = dma_q->bytes_left_in_line;
+ if (bytes_to_copy > length)
+ bytes_to_copy = length;
+
+ if (dma_q->lines_completed >= dma_q->lines_per_field) {
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+ dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ?
+ 0 : 1;
+ return 0;
+ }
+
+ dma_q->is_partial_line = 1;
+
+ /* If we don't have a buffer, just return the number of bytes we would
+ have copied if we had a buffer. */
+ if (!buf) {
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+ dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0)
+ ? 0 : 1;
+ return bytes_to_copy;
+ }
+
+ /* copy the data to video buffer */
+ cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy);
+
+ dma_q->pos += bytes_to_copy;
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+
+ if (dma_q->bytes_left_in_line == 0) {
+ dma_q->bytes_left_in_line = _line_size;
+ dma_q->lines_completed++;
+ dma_q->is_partial_line = 0;
+
+ if (cx231xx_is_buffer_done(dev, dma_q) && buf) {
+ buffer_filled(dev, dma_q, buf);
+
+ dma_q->pos = 0;
+ buf = NULL;
+ dma_q->lines_completed = 0;
+ }
+ }
+
+ return bytes_to_copy;
+}
+
+void cx231xx_reset_video_buffer(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ struct cx231xx_buffer *buf;
+
+ /* handle the switch from field 1 to field 2 */
+ if (dma_q->current_field == 1) {
+ if (dma_q->lines_completed >= dma_q->lines_per_field)
+ dma_q->field1_done = 1;
+ else
+ dma_q->field1_done = 0;
+ }
+
+ buf = dev->video_mode.isoc_ctl.buf;
+
+ if (buf == NULL) {
+ u8 *outp = NULL;
+ /* first try to get the buffer */
+ get_next_buf(dma_q, &buf);
+
+ if (buf)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ dma_q->pos = 0;
+ dma_q->field1_done = 0;
+ dma_q->current_field = -1;
+ }
+
+ /* reset the counters */
+ dma_q->bytes_left_in_line = dev->width << 1;
+ dma_q->lines_completed = 0;
+}
+
+int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_buffer, u32 bytes_to_copy)
+{
+ u8 *p_out_buffer = NULL;
+ u32 current_line_bytes_copied = 0;
+ struct cx231xx_buffer *buf;
+ u32 _line_size = dev->width << 1;
+ void *startwrite;
+ int offset, lencopy;
+
+ buf = dev->video_mode.isoc_ctl.buf;
+
+ if (buf == NULL)
+ return -1;
+
+ p_out_buffer = videobuf_to_vmalloc(&buf->vb);
+
+ current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line;
+
+ /* Offset field 2 one line from the top of the buffer */
+ offset = (dma_q->current_field == 1) ? 0 : _line_size;
+
+ /* Offset for field 2 */
+ startwrite = p_out_buffer + offset;
+
+ /* lines already completed in the current field */
+ startwrite += (dma_q->lines_completed * _line_size * 2);
+
+ /* bytes already completed in the current line */
+ startwrite += current_line_bytes_copied;
+
+ lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
+ bytes_to_copy : dma_q->bytes_left_in_line;
+
+ if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size))
+ return 0;
+
+ /* The below copies the UYVY data straight into video buffer */
+ cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy);
+
+ return 0;
+}
+
+void cx231xx_swab(u16 *from, u16 *to, u16 len)
+{
+ u16 i;
+
+ if (len <= 0)
+ return;
+
+ for (i = 0; i < len / 2; i++)
+ to[i] = (from[i] << 8) | (from[i] >> 8);
+}
+
+u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q)
+{
+ u8 buffer_complete = 0;
+
+ /* Dual field stream */
+ buffer_complete = ((dma_q->current_field == 2) &&
+ (dma_q->lines_completed >= dma_q->lines_per_field) &&
+ dma_q->field1_done);
+
+ return buffer_complete;
+}
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ struct v4l2_frequency f;
+
+ *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3;
+ if (0 == *count)
+ *count = CX231XX_DEF_BUF;
+
+ if (*count < CX231XX_MIN_BUF)
+ *count = CX231XX_MIN_BUF;
+
+ /* Ask tuner to go to analog mode */
+ memset(&f, 0, sizeof(f));
+ f.frequency = dev->ctl_freq;
+ f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+
+ call_all(dev, tuner, s_frequency, &f);
+
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ unsigned long flags = 0;
+
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->video_mode.slock, flags);
+ if (dev->video_mode.isoc_ctl.buf == buf)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->video_mode.slock, flags);
+
+ 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 cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ /* The only currently supported format is 16 bits/pixel */
+ buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+ + 7) >> 3;
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (!dev->video_mode.isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ if (rc < 0)
+ goto fail;
+ }
+
+ 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 cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = (struct cx231xx *)fh->dev;
+
+ cx231xx_isocdbg("cx231xx: called buffer_release\n");
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops cx231xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************* v4l2 interface **************************************/
+
+void video_mux(struct cx231xx *dev, int index)
+{
+
+ struct v4l2_routing route;
+
+ route.input = INPUT(index)->vmux;
+ route.output = 0;
+ dev->video_input = index;
+ dev->ctl_ainput = INPUT(index)->amux;
+
+ cx231xx_set_video_input_mux(dev, index);
+
+ cx25840_call(dev, video, s_routing, &route);
+
+ cx231xx_set_audio_input(dev, dev->ctl_ainput);
+
+ cx231xx_info("video_mux : %d\n", index);
+
+ /* do mode control overrides if required */
+ cx231xx_do_mode_ctrl_overrides(dev);
+}
+
+/* Usage lock check functions */
+static int res_get(struct cx231xx_fh *fh)
+{
+ struct cx231xx *dev = fh->dev;
+ int rc = 0;
+
+ /* This instance already has stream_on */
+ if (fh->stream_on)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (dev->stream_on)
+ return -EBUSY;
+ dev->stream_on = 1;
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (dev->vbi_stream_on)
+ return -EBUSY;
+ dev->vbi_stream_on = 1;
+ } else
+ return -EINVAL;
+
+ fh->stream_on = 1;
+
+ return rc;
+}
+
+static int res_check(struct cx231xx_fh *fh)
+{
+ return fh->stream_on;
+}
+
+static void res_free(struct cx231xx_fh *fh)
+{
+ struct cx231xx *dev = fh->dev;
+
+ fh->stream_on = 0;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ dev->stream_on = 0;
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ dev->vbi_stream_on = 0;
+}
+
+static int check_dev(struct cx231xx *dev)
+{
+ if (dev->state & DEV_DISCONNECTED) {
+ cx231xx_errdev("v4l2 ioctl: device not present\n");
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ cx231xx_errdev("v4l2 ioctl: device is misconfigured; "
+ "close and open it again\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+void get_scale(struct cx231xx *dev,
+ unsigned int width, unsigned int height,
+ unsigned int *hscale, unsigned int *vscale)
+{
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+
+ *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
+ if (*hscale >= 0x4000)
+ *hscale = 0x3fff;
+
+ *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
+ if (*vscale >= 0x4000)
+ *vscale = 0x3fff;
+
+ dev->hscale = *hscale;
+ dev->vscale = *vscale;
+
+}
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ mutex_lock(&dev->lock);
+
+ 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.sizeimage = f->fmt.pix.bytesperline * dev->height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(format); i++)
+ if (format[i].fourcc == fourcc)
+ return &format[i];
+
+ return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int width = f->fmt.pix.width;
+ int height = f->fmt.pix.height;
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+ unsigned int hscale, vscale;
+ struct cx231xx_fmt *fmt;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ cx231xx_videodbg("Fourcc format (%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ /* width must even because of the YUYV format
+ height must be even because of interlacing */
+ height &= 0xfffe;
+ width &= 0xfffe;
+
+ if (unlikely(height < 32))
+ height = 32;
+ if (unlikely(height > maxh))
+ height = maxh;
+ if (unlikely(width < 48))
+ width = 48;
+ if (unlikely(width > maxw))
+ width = maxw;
+
+ get_scale(dev, width, height, &hscale, &vscale);
+
+ width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+ height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ f->fmt.pix.width = width;
+ f->fmt.pix.height = height;
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+ struct cx231xx_fmt *fmt;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+
+ vidioc_try_fmt_vid_cap(file, priv, f);
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ cx231xx_errdev("%s queue busy\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
+
+ if (dev->stream_on && !fh->stream_on) {
+ cx231xx_errdev("%s device in use by another fh\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
+
+ /* set new image size */
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ dev->format = fmt;
+ get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+ call_all(dev, video, s_fmt, f);
+
+ /* Set the correct alternate setting for this resolution */
+ cx231xx_resolution_set(dev);
+
+out:
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id * id)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ *id = dev->norm;
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ struct v4l2_format f;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
+
+ mutex_lock(&dev->lock);
+ dev->norm = *norm;
+
+ /* Adjusts width/height, if needed */
+ f.fmt.pix.width = dev->width;
+ f.fmt.pix.height = dev->height;
+ vidioc_try_fmt_vid_cap(file, priv, &f);
+
+ /* set new image size */
+ dev->width = f.fmt.pix.width;
+ dev->height = f.fmt.pix.height;
+ get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+ call_all(dev, tuner, s_std, dev->norm);
+
+ mutex_unlock(&dev->lock);
+
+ cx231xx_resolution_set(dev);
+
+ /* do mode control overrides */
+ cx231xx_do_mode_ctrl_overrides(dev);
+
+ return 0;
+}
+
+static const char *iname[] = {
+ [CX231XX_VMUX_COMPOSITE1] = "Composite1",
+ [CX231XX_VMUX_SVIDEO] = "S-Video",
+ [CX231XX_VMUX_TELEVISION] = "Television",
+ [CX231XX_VMUX_CABLE] = "Cable TV",
+ [CX231XX_VMUX_DVB] = "DVB",
+ [CX231XX_VMUX_DEBUG] = "for debug only",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ unsigned int n;
+
+ n = i->index;
+ if (n >= MAX_CX231XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strcpy(i->name, iname[INPUT(n)->type]);
+
+ if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
+ (CX231XX_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+
+ i->std = dev->vdev->tvnorms;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ *i = dev->video_input;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (i >= MAX_CX231XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(i)->type)
+ return -EINVAL;
+
+ mutex_lock(&dev->lock);
+
+ video_mux(dev, i);
+
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ switch (a->index) {
+ case CX231XX_AMUX_VIDEO:
+ strcpy(a->name, "Television");
+ break;
+ case CX231XX_AMUX_LINE_IN:
+ strcpy(a->name, "Line In");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ a->index = dev->ctl_ainput;
+ a->capability = V4L2_AUDCAP_STEREO;
+
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int status = 0;
+
+ /* Doesn't allow manual routing */
+ if (a->index != dev->ctl_ainput)
+ return -EINVAL;
+
+ dev->ctl_ainput = INPUT(a->index)->amux;
+ status = cx231xx_set_audio_input(dev, dev->ctl_ainput);
+
+ return status;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int id = qc->id;
+ int i;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
+ if (unlikely(qc->id == 0))
+ return -EINVAL;
+
+ memset(qc, 0, sizeof(*qc));
+
+ qc->id = id;
+
+ if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+
+ for (i = 0; i < CX231XX_CTLS; i++)
+ if (cx231xx_ctls[i].v.id == qc->id)
+ break;
+
+ if (i == CX231XX_CTLS) {
+ *qc = no_ctl;
+ return 0;
+ }
+ *qc = cx231xx_ctls[i].v;
+
+ mutex_lock(&dev->lock);
+ call_all(dev, core, queryctrl, qc);
+ mutex_unlock(&dev->lock);
+
+ if (qc->type)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ call_all(dev, core, g_ctrl, ctrl);
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ call_all(dev, core, s_ctrl, ctrl);
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ strcpy(t->name, "Tuner");
+
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
+ t->signal = 0xffff; /* LOCKED */
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != t->index)
+ return -EINVAL;
+#if 0 /* Keep */
+ mutex_lock(&dev->lock);
+ call_all(dev, tuner, s_tuner, t);
+ mutex_unlock(&dev->lock);
+#endif
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ mutex_lock(&dev->lock);
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->ctl_freq;
+
+ call_all(dev, tuner, g_frequency, f);
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != f->tuner)
+ return -EINVAL;
+
+ if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+ return -EINVAL;
+ if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+ return -EINVAL;
+
+ /* set pre channel change settings in DIF first */
+ rc = cx231xx_tuner_pre_channel_change(dev);
+
+ mutex_lock(&dev->lock);
+
+ dev->ctl_freq = f->frequency;
+
+ if (dev->tuner_type == TUNER_XC5000) {
+ if (dev->cx231xx_set_analog_freq != NULL)
+ dev->cx231xx_set_analog_freq(dev, f->frequency);
+ } else
+ call_all(dev, tuner, s_frequency, f);
+
+ mutex_unlock(&dev->lock);
+
+ /* set post channel change settings in DIF first */
+ rc = cx231xx_tuner_post_channel_change(dev);
+
+ cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
+
+ return rc;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+/*
+ -R, --list-registers=type=<host/i2cdrv/i2caddr>,
+ chip=<chip>[,min=<addr>,max=<addr>]
+ dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]
+ -r, --set-register=type=<host/i2cdrv/i2caddr>,
+ chip=<chip>,reg=<addr>,val=<val>
+ set the register [VIDIOC_DBG_S_REGISTER]
+
+ if type == host, then <chip> is the hosts chip ID (default 0)
+ if type == i2cdrv (default), then <chip> is the I2C driver name or ID
+ if type == i2caddr, then <chip> is the 7-bit I2C address
+*/
+
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int ret = 0;
+ u8 value[4] = { 0, 0, 0, 0 };
+ u32 data = 0;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ switch (reg->match.addr) {
+ case 0: /* Cx231xx - internal registers */
+ ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+ (u16)reg->reg, value, 4);
+ reg->val = value[0] | value[1] << 8 |
+ value[2] << 16 | value[3] << 24;
+ break;
+ case 1: /* AFE - read byte */
+ ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, &data, 1);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 14: /* AFE - read dword */
+ ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, &data, 4);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 2: /* Video Block - read byte */
+ ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, &data, 1);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 24: /* Video Block - read dword */
+ ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, &data, 4);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 3: /* I2S block - read byte */
+ ret = cx231xx_read_i2c_data(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ &data, 1);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 34: /* I2S Block - read dword */
+ ret =
+ cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1, &data, 4);
+ reg->val = le32_to_cpu(data);
+ break;
+ }
+ return ret < 0 ? ret : 0;
+
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ call_all(dev, core, g_register, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ /* Not supported yet */
+ return -EINVAL;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->lock);
+ call_all(dev, core, g_register, reg);
+ mutex_unlock(&dev->lock);
+
+ return ret;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int ret = 0;
+ __le64 buf;
+ u32 value;
+ u8 data[4] = { 0, 0, 0, 0 };
+
+ buf = cpu_to_le64(reg->val);
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ {
+ value = (u32) buf & 0xffffffff;
+
+ switch (reg->match.addr) {
+ case 0: /* cx231xx internal registers */
+ data[0] = (u8) value;
+ data[1] = (u8) (value >> 8);
+ data[2] = (u8) (value >> 16);
+ data[3] = (u8) (value >> 24);
+ ret = cx231xx_write_ctrl_reg(dev,
+ VRT_SET_REGISTER,
+ (u16)reg->reg, data,
+ 4);
+ break;
+ case 1: /* AFE - read byte */
+ ret = cx231xx_write_i2c_data(dev,
+ AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1);
+ break;
+ case 14: /* AFE - read dword */
+ ret = cx231xx_write_i2c_data(dev,
+ AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 4);
+ break;
+ case 2: /* Video Block - read byte */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1);
+ break;
+ case 24: /* Video Block - read dword */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 4);
+ break;
+ case 3: /* I2S block - read byte */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ value, 1);
+ break;
+ case 34: /* I2S block - read dword */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ value, 4);
+ break;
+ }
+ }
+ return ret < 0 ? ret : 0;
+
+ default:
+ break;
+ }
+
+ mutex_lock(&dev->lock);
+ call_all(dev, core, s_register, reg);
+ mutex_unlock(&dev->lock);
+
+ return ret;
+}
+#endif
+
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cc)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+ cc->pixelaspect.denominator = 59;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+
+ if (likely(rc >= 0))
+ rc = videobuf_streamon(&fh->vb_vidq);
+
+ call_all(dev, video, s_stream, 1);
+
+ mutex_unlock(&dev->lock);
+
+ return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+ if (type != fh->type)
+ return -EINVAL;
+
+ mutex_lock(&dev->lock);
+
+ cx25840_call(dev, video, s_stream, 0);
+
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
+ strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->version = CX231XX_VERSION_CODE;
+
+ cap->capabilities = V4L2_CAP_VBI_CAPTURE |
+#if 0 /* Keep */
+ V4L2_CAP_SLICED_VBI_CAPTURE |
+#endif
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
+ if (dev->tuner_type != TUNER_ABSENT)
+ cap->capabilities |= V4L2_CAP_TUNER;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(format)))
+ return -EINVAL;
+
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
+
+ return 0;
+}
+
+/* Sliced VBI ioctls */
+static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+
+ f->fmt.sliced.service_set = 0;
+
+ call_all(dev, video, g_fmt, f);
+
+ if (f->fmt.sliced.service_set == 0)
+ rc = -EINVAL;
+
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ call_all(dev, video, g_fmt, f);
+ mutex_unlock(&dev->lock);
+
+ if (f->fmt.sliced.service_set == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ f->fmt.vbi.sampling_rate = (dev->norm & V4L2_STD_625_50) ?
+ 35468950 : 28636363;
+ f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+ f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.vbi.offset = 64 * 4;
+ f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
+ f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES;
+ f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
+ f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+
+ return 0;
+
+}
+
+static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ if (dev->vbi_stream_on && !fh->stream_on) {
+ cx231xx_errdev("%s device in use by another fh\n", __func__);
+ return -EBUSY;
+ }
+
+ f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ f->fmt.vbi.sampling_rate = (dev->norm & V4L2_STD_625_50) ?
+ 35468950 : 28636363;
+ f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+ f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.vbi.offset = 244;
+ f->fmt.vbi.flags = 0;
+ f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
+ f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES;
+ f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
+ f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+
+ return 0;
+
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct cx231xx_fh *fh = priv;
+
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+ strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
+ strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->version = CX231XX_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+ if (unlikely(t->index > 0))
+ return -EINVAL;
+
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+
+ mutex_lock(&dev->lock);
+ call_all(dev, tuner, s_tuner, t);
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
+ strcpy(i->name, "Radio");
+ i->type = V4L2_INPUT_TYPE_TUNER;
+
+ return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ if (unlikely(a->index))
+ return -EINVAL;
+
+ strcpy(a->name, "Radio");
+ return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ mutex_lock(&dev->lock);
+ call_all(dev, tuner, s_tuner, t);
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int radio_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ return 0;
+}
+
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+ return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ int i;
+
+ if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
+ for (i = 0; i < CX231XX_CTLS; i++)
+ if (cx231xx_ctls[i].v.id == c->id)
+ break;
+ *c = cx231xx_ctls[i].v;
+ } else
+ *c = no_ctl;
+ return 0;
+}
+
+/*
+ * cx231xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int cx231xx_v4l2_open(struct file *filp)
+{
+ int minor = video_devdata(filp)->minor;
+ int errCode = 0, radio = 0;
+ struct cx231xx *dev = NULL;
+ struct cx231xx_fh *fh;
+ enum v4l2_buf_type fh_type = 0;
+
+ dev = cx231xx_get_device(minor, &fh_type, &radio);
+ if (NULL == dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->lock);
+
+ cx231xx_videodbg("open minor=%d type=%s users=%d\n",
+ minor, v4l2_type_names[fh_type], dev->users);
+
+#if 0 /* Keep */
+ errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("Device locked on digital mode. Can't open analog\n");
+ mutex_unlock(&dev->lock);
+ return -EBUSY;
+ }
+#endif
+
+ fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
+ if (!fh) {
+ cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
+ mutex_unlock(&dev->lock);
+ return -ENOMEM;
+ }
+ fh->dev = dev;
+ fh->radio = radio;
+ fh->type = fh_type;
+ filp->private_data = fh;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+ dev->hscale = 0;
+ dev->vscale = 0;
+
+ /* Power up in Analog TV mode */
+ cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
+
+#if 0 /* Keep */
+ cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+#endif
+ cx231xx_resolution_set(dev);
+
+ /* set video alternate setting */
+ cx231xx_set_video_alternate(dev);
+
+ /* Needed, since GPIO might have disabled power of
+ some i2c device */
+ cx231xx_config_i2c(dev);
+
+ /* device needs to be initialized before isoc transfer */
+ dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+ video_mux(dev, dev->video_input);
+
+ }
+ if (fh->radio) {
+ cx231xx_videodbg("video_open: setting radio device\n");
+
+ /* cx231xx_start_radio(dev); */
+
+ call_all(dev, tuner, s_radio);
+ }
+
+ dev->users++;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops,
+ NULL, &dev->video_mode.slock,
+ fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct cx231xx_buffer), fh);
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ /* Set the required alternate setting VBI interface works in
+ Bulk mode only */
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
+ NULL, &dev->vbi_mode.slock,
+ fh->type, V4L2_FIELD_SEQ_TB,
+ sizeof(struct cx231xx_buffer), fh);
+ }
+
+ mutex_unlock(&dev->lock);
+
+ return errCode;
+}
+
+/*
+ * cx231xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void cx231xx_release_analog_resources(struct cx231xx *dev)
+{
+
+ /*FIXME: I2C IR should be disconnected */
+
+ if (dev->radio_dev) {
+ if (-1 != dev->radio_dev->minor)
+ video_unregister_device(dev->radio_dev);
+ else
+ video_device_release(dev->radio_dev);
+ dev->radio_dev = NULL;
+ }
+ if (dev->vbi_dev) {
+ cx231xx_info("V4L2 device /dev/vbi%d deregistered\n",
+ dev->vbi_dev->num);
+ if (-1 != dev->vbi_dev->minor)
+ video_unregister_device(dev->vbi_dev);
+ else
+ video_device_release(dev->vbi_dev);
+ dev->vbi_dev = NULL;
+ }
+ if (dev->vdev) {
+ cx231xx_info("V4L2 device /dev/video%d deregistered\n",
+ dev->vdev->num);
+ if (-1 != dev->vdev->minor)
+ video_unregister_device(dev->vdev);
+ else
+ video_device_release(dev->vdev);
+ dev->vdev = NULL;
+ }
+}
+
+/*
+ * cx231xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
+ */
+static int cx231xx_v4l2_close(struct file *filp)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ cx231xx_videodbg("users=%d\n", dev->users);
+
+ mutex_lock(&dev->lock);
+
+ if (res_check(fh))
+ res_free(fh);
+
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ /* the device is already disconnect,
+ free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ cx231xx_release_resources(dev);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return 0;
+ }
+
+ /* do this before setting alternate! */
+ cx231xx_uninit_vbi_isoc(dev);
+
+ /* set alternate 0 */
+ if (!dev->vbi_or_sliced_cc_mode)
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+ else
+ cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+
+ kfree(fh);
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
+
+ if (dev->users == 1) {
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ /* the device is already disconnect,
+ free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ cx231xx_release_resources(dev);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return 0;
+ }
+
+ /* Save some power by putting tuner to sleep */
+ call_all(dev, core, s_standby, 0);
+
+ /* do this before setting alternate! */
+ cx231xx_uninit_isoc(dev);
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+ /* set alternate 0 */
+ cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
+ }
+ kfree(fh);
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+/*
+ * cx231xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+ (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) {
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return rc;
+
+ return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+ return 0;
+}
+
+/*
+ * cx231xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table * wait)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return POLLERR;
+
+ if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
+ (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type))
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ else
+ return POLLERR;
+}
+
+/*
+ * cx231xx_v4l2_mmap()
+ */
+static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+ rc = res_get(fh);
+ mutex_unlock(&dev->lock);
+
+ if (unlikely(rc < 0))
+ return rc;
+
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+ cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end -
+ (unsigned long)vma->vm_start, rc);
+
+ return rc;
+}
+
+static const struct v4l2_file_operations cx231xx_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = cx231xx_v4l2_open,
+ .release = cx231xx_v4l2_close,
+ .read = cx231xx_v4l2_read,
+ .poll = cx231xx_v4l2_poll,
+ .mmap = cx231xx_v4l2_mmap,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_cropcap = vidioc_cropcap,
+ .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
+ .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+};
+
+static struct video_device cx231xx_vbi_template;
+
+static const struct video_device cx231xx_video_template = {
+ .fops = &cx231xx_v4l_fops,
+ .release = video_device_release,
+ .ioctl_ops = &video_ioctl_ops,
+ .minor = -1,
+ .tvnorms = V4L2_STD_ALL,
+ .current_norm = V4L2_STD_PAL,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = cx231xx_v4l2_open,
+ .release = cx231xx_v4l2_close,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+ .vidioc_querycap = radio_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_enum_input = radio_enum_input,
+ .vidioc_g_audio = radio_g_audio,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_s_audio = radio_s_audio,
+ .vidioc_s_input = radio_s_input,
+ .vidioc_queryctrl = radio_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+static struct video_device cx231xx_radio_template = {
+ .name = "cx231xx-radio",
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+ .minor = -1,
+};
+
+/******************************** usb interface ******************************/
+
+static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
+ const struct video_device
+ *template, const char *type_name)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+
+ *vfd = *template;
+ vfd->minor = -1;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->debug = video_debug;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
+
+ return vfd;
+}
+
+int cx231xx_register_analog_devices(struct cx231xx *dev)
+{
+ int ret;
+
+ cx231xx_info("%s: v4l2 driver version %d.%d.%d\n",
+ dev->name,
+ (CX231XX_VERSION_CODE >> 16) & 0xff,
+ (CX231XX_VERSION_CODE >> 8) & 0xff,
+ CX231XX_VERSION_CODE & 0xff);
+
+ /* set default norm */
+ /*dev->norm = cx231xx_video_template.current_norm; */
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+ dev->interlaced = 0;
+ dev->hscale = 0;
+ dev->vscale = 0;
+
+ /* Analog specific initialization */
+ dev->format = &format[0];
+ /* video_mux(dev, dev->video_input); */
+
+ /* Audio defaults */
+ dev->mute = 1;
+ dev->volume = 0x1f;
+
+ /* enable vbi capturing */
+ /* write code here... */
+
+ /* allocate and fill video video_device struct */
+ dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video");
+ if (!dev->vdev) {
+ cx231xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+
+ /* register v4l2 video video_device */
+ ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ video_nr[dev->devno]);
+ if (ret) {
+ cx231xx_errdev("unable to register video device (error=%i).\n",
+ ret);
+ return ret;
+ }
+
+ cx231xx_info("%s/0: registered device video%d [v4l2]\n",
+ dev->name, dev->vdev->num);
+
+ /* Initialize VBI template */
+ memcpy(&cx231xx_vbi_template, &cx231xx_video_template,
+ sizeof(cx231xx_vbi_template));
+ strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
+
+ /* Allocate and fill vbi video_device struct */
+ dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
+
+ /* register v4l2 vbi video_device */
+ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ vbi_nr[dev->devno]);
+ if (ret < 0) {
+ cx231xx_errdev("unable to register vbi device\n");
+ return ret;
+ }
+
+ cx231xx_info("%s/0: registered device vbi%d\n",
+ dev->name, dev->vbi_dev->num);
+
+ if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
+ dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
+ "radio");
+ if (!dev->radio_dev) {
+ cx231xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+ ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ radio_nr[dev->devno]);
+ if (ret < 0) {
+ cx231xx_errdev("can't register radio device\n");
+ return ret;
+ }
+ cx231xx_info("Registered radio device as /dev/radio%d\n",
+ dev->radio_dev->num);
+ }
+
+ cx231xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
+ dev->vdev->num, dev->vbi_dev->num);
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx231xx/cx231xx.h b/linux/drivers/media/video/cx231xx/cx231xx.h
new file mode 100644
index 000000000..21b4023dd
--- /dev/null
+++ b/linux/drivers/media/video/cx231xx/cx231xx.h
@@ -0,0 +1,788 @@
+/*
+ cx231xx.h - driver for Conexant Cx23100/101/102 USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+
+ 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.
+ */
+
+#ifndef _CX231XX_H
+#define _CX231XX_H
+
+#include <linux/videodev2.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/mutex.h>
+
+#include "compat.h"
+
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/ir-kbd-i2c.h>
+#if defined(CONFIG_VIDEO_CX231XX_DVB) || \
+ defined(CONFIG_VIDEO_CX231XX_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+
+#include "cx231xx-reg.h"
+#include "cx231xx-pcb-cfg.h"
+#include "cx231xx-conf-reg.h"
+
+#define DRIVER_NAME "cx231xx"
+#define PWR_SLEEP_INTERVAL 5
+
+/* I2C addresses for control block in Cx231xx */
+#define AFE_DEVICE_ADDRESS 0x60
+#define I2S_BLK_DEVICE_ADDRESS 0x98
+#define VID_BLK_I2C_ADDRESS 0x88
+#define DIF_USE_BASEBAND 0xFFFFFFFF
+
+/* Boards supported by driver */
+#define CX231XX_BOARD_UNKNOWN 0
+#define CX231XX_BOARD_CNXT_RDE_250 1
+#define CX231XX_BOARD_CNXT_RDU_250 2
+
+/* Limits minimum and default number of buffers */
+#define CX231XX_MIN_BUF 4
+#define CX231XX_DEF_BUF 12
+#define CX231XX_DEF_VBI_BUF 6
+
+#define VBI_LINE_COUNT 17
+#define VBI_LINE_LENGTH 1440
+
+/*Limits the max URB message size */
+#define URB_MAX_CTRL_SIZE 80
+
+/* Params for validated field */
+#define CX231XX_BOARD_NOT_VALIDATED 1
+#define CX231XX_BOARD_VALIDATED 0
+
+/* maximum number of cx231xx boards */
+#define CX231XX_MAXBOARDS 8
+
+/* maximum number of frames that can be queued */
+#define CX231XX_NUM_FRAMES 5
+
+/* number of buffers for isoc transfers */
+#define CX231XX_NUM_BUFS 8
+
+/* number of packets for each buffer
+ windows requests only 40 packets .. so we better do the same
+ this is what I found out for all alternate numbers there!
+ */
+#define CX231XX_NUM_PACKETS 40
+
+/* default alternate; 0 means choose the best */
+#define CX231XX_PINOUT 0
+
+#define CX231XX_INTERLACED_DEFAULT 1
+
+/* time to wait when stopping the isoc transfer */
+#define CX231XX_URB_TIMEOUT \
+ msecs_to_jiffies(CX231XX_NUM_BUFS * CX231XX_NUM_PACKETS)
+
+enum cx231xx_mode {
+ CX231XX_SUSPEND,
+ CX231XX_ANALOG_MODE,
+ CX231XX_DIGITAL_MODE,
+};
+
+enum cx231xx_std_mode {
+ CX231XX_TV_AIR = 0,
+ CX231XX_TV_CABLE
+};
+
+enum cx231xx_stream_state {
+ STREAM_OFF,
+ STREAM_INTERRUPT,
+ STREAM_ON,
+};
+
+struct cx231xx;
+
+struct cx231xx_usb_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct cx231xx_buffer *buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+
+ /* isoc urb callback */
+ int (*isoc_copy) (struct cx231xx *dev, struct urb *urb);
+};
+
+struct cx231xx_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+ int depth;
+ int reg;
+};
+
+/* buffer for one video frame */
+struct cx231xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ struct list_head frame;
+ int top_field;
+ int receiving;
+};
+
+struct cx231xx_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+
+ wait_queue_head_t wq;
+
+ /* Counters to control buffer fill */
+ int pos;
+ u8 is_partial_line;
+ u8 partial_buf[8];
+ u8 last_sav;
+ int current_field;
+ u32 bytes_left_in_line;
+ u32 lines_completed;
+ u8 field1_done;
+ u32 lines_per_field;
+};
+
+/* inputs */
+
+#define MAX_CX231XX_INPUT 4
+
+enum cx231xx_itype {
+ CX231XX_VMUX_COMPOSITE1 = 1,
+ CX231XX_VMUX_SVIDEO,
+ CX231XX_VMUX_TELEVISION,
+ CX231XX_VMUX_CABLE,
+ CX231XX_RADIO,
+ CX231XX_VMUX_DVB,
+ CX231XX_VMUX_DEBUG
+};
+
+enum cx231xx_v_input {
+ CX231XX_VIN_1_1 = 0x1,
+ CX231XX_VIN_2_1,
+ CX231XX_VIN_3_1,
+ CX231XX_VIN_4_1,
+ CX231XX_VIN_1_2 = 0x01,
+ CX231XX_VIN_2_2,
+ CX231XX_VIN_3_2,
+ CX231XX_VIN_1_3 = 0x1,
+ CX231XX_VIN_2_3,
+ CX231XX_VIN_3_3,
+};
+
+/* cx231xx has two audio inputs: tuner and line in */
+enum cx231xx_amux {
+ /* This is the only entry for cx231xx tuner input */
+ CX231XX_AMUX_VIDEO, /* cx231xx tuner */
+ CX231XX_AMUX_LINE_IN, /* Line In */
+};
+
+struct cx231xx_reg_seq {
+ unsigned char bit;
+ unsigned char val;
+ int sleep;
+};
+
+struct cx231xx_input {
+ enum cx231xx_itype type;
+ unsigned int vmux;
+ enum cx231xx_amux amux;
+ struct cx231xx_reg_seq *gpio;
+};
+
+#define INPUT(nr) (&cx231xx_boards[dev->model].input[nr])
+
+enum cx231xx_decoder {
+ CX231XX_NODECODER,
+ CX231XX_AVDECODER
+};
+
+enum CX231XX_I2C_MASTER_PORT {
+ I2C_0 = 0,
+ I2C_1 = 1,
+ I2C_2 = 2,
+ I2C_3 = 3
+};
+
+struct cx231xx_board {
+ char *name;
+ int vchannels;
+ int tuner_type;
+ int tuner_addr;
+ v4l2_std_id norm; /* tv norm */
+
+ /* demod related */
+ int demod_addr;
+ u8 demod_xfer_mode; /* 0 - Serial; 1 - parallel */
+
+ /* GPIO Pins */
+ struct cx231xx_reg_seq *dvb_gpio;
+ struct cx231xx_reg_seq *suspend_gpio;
+ struct cx231xx_reg_seq *tuner_gpio;
+ u8 tuner_sif_gpio;
+ u8 tuner_scl_gpio;
+ u8 tuner_sda_gpio;
+
+ /* PIN ctrl */
+ u32 ctl_pin_status_mask;
+ u8 agc_analog_digital_select_gpio;
+ u32 gpio_pin_status_mask;
+
+ /* i2c masters */
+ u8 tuner_i2c_master;
+ u8 demod_i2c_master;
+
+ unsigned int max_range_640_480:1;
+ unsigned int has_dvb:1;
+ unsigned int valid:1;
+
+ unsigned char xclk, i2c_speed;
+
+ enum cx231xx_decoder decoder;
+
+ struct cx231xx_input input[MAX_CX231XX_INPUT];
+ struct cx231xx_input radio;
+ IR_KEYTAB_TYPE *ir_codes;
+};
+
+/* device states */
+enum cx231xx_dev_state {
+ DEV_INITIALIZED = 0x01,
+ DEV_DISCONNECTED = 0x02,
+ DEV_MISCONFIGURED = 0x04,
+};
+
+enum AFE_MODE {
+ AFE_MODE_LOW_IF,
+ AFE_MODE_BASEBAND,
+ AFE_MODE_EU_HI_IF,
+ AFE_MODE_US_HI_IF,
+ AFE_MODE_JAPAN_HI_IF
+};
+
+enum AUDIO_INPUT {
+ AUDIO_INPUT_MUTE,
+ AUDIO_INPUT_LINE,
+ AUDIO_INPUT_TUNER_TV,
+ AUDIO_INPUT_SPDIF,
+ AUDIO_INPUT_TUNER_FM
+};
+
+#define CX231XX_AUDIO_BUFS 5
+#define CX231XX_NUM_AUDIO_PACKETS 64
+#define CX231XX_CAPTURE_STREAM_EN 1
+#define CX231XX_STOP_AUDIO 0
+#define CX231XX_START_AUDIO 1
+
+/* cx231xx extensions */
+#define CX231XX_AUDIO 0x10
+#define CX231XX_DVB 0x20
+
+struct cx231xx_audio {
+ char name[50];
+ char *transfer_buffer[CX231XX_AUDIO_BUFS];
+ struct urb *urb[CX231XX_AUDIO_BUFS];
+ struct usb_device *udev;
+ unsigned int capture_transfer_done;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ snd_pcm_substream_t *capture_pcm_substream;
+#else
+ struct snd_pcm_substream *capture_pcm_substream;
+#endif
+
+ unsigned int hwptr_done_capture;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
+ snd_card_t *sndcard;
+#else
+ struct snd_card *sndcard;
+#endif
+
+ int users, shutdown;
+ enum cx231xx_stream_state capture_stream;
+ spinlock_t slock;
+
+ int alt; /* alternate */
+ int max_pkt_size; /* max packet size of isoc transaction */
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ u16 end_point_addr;
+};
+
+struct cx231xx;
+
+struct cx231xx_fh {
+ struct cx231xx *dev;
+ unsigned int stream_on:1; /* Locks streams */
+ int radio;
+
+ struct videobuf_queue vb_vidq;
+
+ enum v4l2_buf_type type;
+};
+
+/*****************************************************************/
+/* set/get i2c */
+/* 00--1Mb/s, 01-400kb/s, 10--100kb/s, 11--5Mb/s */
+#define I2C_SPEED_1M 0x0
+#define I2C_SPEED_400K 0x1
+#define I2C_SPEED_100K 0x2
+#define I2C_SPEED_5M 0x3
+
+/* 0-- STOP transaction */
+#define I2C_STOP 0x0
+/* 1-- do not transmit STOP at end of transaction */
+#define I2C_NOSTOP 0x1
+/* 1--alllow slave to insert clock wait states */
+#define I2C_SYNC 0x1
+
+struct cx231xx_i2c {
+ struct cx231xx *dev;
+
+ int nr;
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+
+ /* different settings for each bus */
+ u8 i2c_period;
+ u8 i2c_nostop;
+ u8 i2c_reserve;
+};
+
+struct cx231xx_i2c_xfer_data {
+ u8 dev_addr;
+ u8 direction; /* 1 - IN, 0 - OUT */
+ u8 saddr_len; /* sub address len */
+ u16 saddr_dat; /* sub addr data */
+ u8 buf_size; /* buffer size */
+ u8 *p_buffer; /* pointer to the buffer */
+};
+
+struct VENDOR_REQUEST_IN {
+ u8 bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+ u8 direction;
+ u8 bData;
+ u8 *pBuff;
+};
+
+struct cx231xx_ctrl {
+ struct v4l2_queryctrl v;
+ u32 off;
+ u32 reg;
+ u32 mask;
+ u32 shift;
+};
+
+enum TRANSFER_TYPE {
+ Raw_Video = 0,
+ Audio,
+ Vbi, /* VANC */
+ Sliced_cc, /* HANC */
+ TS1_serial_mode,
+ TS2,
+ TS1_parallel_mode
+} ;
+
+struct cx231xx_video_mode {
+ /* Isoc control struct */
+ struct cx231xx_dmaqueue vidq;
+ struct cx231xx_usb_isoc_ctl isoc_ctl;
+ spinlock_t slock;
+
+ /* usb transfer */
+ int alt; /* alternate */
+ int max_pkt_size; /* max packet size of isoc transaction */
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ u16 end_point_addr;
+};
+
+/* main device struct */
+struct cx231xx {
+ /* generic device properties */
+ char name[30]; /* name (including minor) of the device */
+ int model; /* index in the device_data struct */
+ int devno; /* marks the number of this device */
+
+ struct cx231xx_board board;
+
+ unsigned int stream_on:1; /* Locks streams */
+ unsigned int vbi_stream_on:1; /* Locks streams for VBI */
+ unsigned int has_audio_class:1;
+ unsigned int has_alsa_audio:1;
+
+ struct cx231xx_fmt *format;
+
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev *sd_cx25840;
+ struct v4l2_subdev *sd_tuner;
+
+ struct cx231xx_IR *ir;
+
+ struct list_head devlist;
+
+ int tuner_type; /* type of the tuner */
+ int tuner_addr; /* tuner address */
+
+ /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+ struct cx231xx_i2c i2c_bus[3];
+ unsigned int xc_fw_load_done:1;
+ struct mutex gpio_i2c_lock;
+
+ /* video for linux */
+ int users; /* user count for exclusive use */
+ struct video_device *vdev; /* video for linux device struct */
+ v4l2_std_id norm; /* selected tv norm */
+ int ctl_freq; /* selected frequency */
+ unsigned int ctl_ainput; /* selected audio input */
+ int mute;
+ int volume;
+
+ /* frame properties */
+ int width; /* current frame width */
+ int height; /* current frame height */
+ unsigned hscale; /* horizontal scale factor (see datasheet) */
+ unsigned vscale; /* vertical scale factor (see datasheet) */
+ int interlaced; /* 1=interlace fileds, 0=just top fileds */
+
+ struct cx231xx_audio adev;
+
+ /* states */
+ enum cx231xx_dev_state state;
+
+ struct work_struct request_module_wk;
+
+ /* locks */
+ struct mutex lock;
+ struct mutex ctrl_urb_lock; /* protects urb_buf */
+ struct list_head inqueue, outqueue;
+ wait_queue_head_t open, wait_frame, wait_stream;
+ struct video_device *vbi_dev;
+ struct video_device *radio_dev;
+
+ unsigned char eedata[256];
+
+ struct cx231xx_video_mode video_mode;
+ struct cx231xx_video_mode vbi_mode;
+ struct cx231xx_video_mode sliced_cc_mode;
+ struct cx231xx_video_mode ts1_mode;
+
+ struct usb_device *udev; /* the usb device */
+ char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
+
+ /* helper funcs that call usb_control_msg */
+ int (*cx231xx_read_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*cx231xx_write_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*cx231xx_send_usb_command) (struct cx231xx_i2c *i2c_bus,
+ struct cx231xx_i2c_xfer_data *req_data);
+ int (*cx231xx_gpio_i2c_read) (struct cx231xx *dev, u8 dev_addr,
+ u8 *buf, u8 len);
+ int (*cx231xx_gpio_i2c_write) (struct cx231xx *dev, u8 dev_addr,
+ u8 *buf, u8 len);
+
+ int (*cx231xx_set_analog_freq) (struct cx231xx *dev, u32 freq);
+ int (*cx231xx_reset_analog_tuner) (struct cx231xx *dev);
+
+ enum cx231xx_mode mode;
+
+ struct cx231xx_dvb *dvb;
+
+ /* Cx231xx supported PCB config's */
+ struct pcb_config current_pcb_config;
+ u8 current_scenario_idx;
+ u8 interface_count;
+ u8 max_iad_interface_count;
+
+ /* GPIO related register direction and values */
+ u32 gpio_dir;
+ u32 gpio_val;
+
+ /* Power Modes */
+ int power_mode;
+
+ /* afe parameters */
+ enum AFE_MODE afe_mode;
+ u32 afe_ref_count;
+
+ /* video related parameters */
+ u32 video_input;
+ u32 active_mode;
+ u8 vbi_or_sliced_cc_mode; /* 0 - vbi ; 1 - sliced cc mode */
+ enum cx231xx_std_mode std_mode; /* 0 - Air; 1 - cable */
+
+};
+
+#define cx25840_call(cx231xx, o, f, args...) \
+ v4l2_subdev_call(cx231xx->sd_cx25840, o, f, ##args)
+#define tuner_call(cx231xx, o, f, args...) \
+ v4l2_subdev_call(cx231xx->sd_tuner, o, f, ##args)
+#define call_all(dev, o, f, args...) \
+ v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
+
+struct cx231xx_ops {
+ struct list_head next;
+ char *name;
+ int id;
+ int (*init) (struct cx231xx *);
+ int (*fini) (struct cx231xx *);
+};
+
+/* call back functions in dvb module */
+int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq);
+int cx231xx_reset_analog_tuner(struct cx231xx *dev);
+
+/* Provided by cx231xx-i2c.c */
+void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c);
+int cx231xx_i2c_register(struct cx231xx_i2c *bus);
+int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
+
+/* Internal block control functions */
+int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr,
+ u16 saddr, u8 saddr_len, u32 *data, u8 data_len);
+int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr,
+ u16 saddr, u8 saddr_len, u32 data, u8 data_len);
+int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size,
+ u16 register_address, u8 bit_start, u8 bit_end,
+ u32 value);
+int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr,
+ u16 saddr, u32 mask, u32 value);
+u32 cx231xx_set_field(u32 field_mask, u32 data);
+
+/* afe related functions */
+int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count);
+int cx231xx_afe_init_channels(struct cx231xx *dev);
+int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev);
+int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux);
+int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode);
+int cx231xx_afe_update_power_control(struct cx231xx *dev,
+ enum AV_MODE avmode);
+int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input);
+
+/* i2s block related functions */
+int cx231xx_i2s_blk_initialize(struct cx231xx *dev);
+int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev,
+ enum AV_MODE avmode);
+int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input);
+
+/* DIF related functions */
+int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
+ u32 function_mode, u32 standard);
+int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard);
+int cx231xx_tuner_pre_channel_change(struct cx231xx *dev);
+int cx231xx_tuner_post_channel_change(struct cx231xx *dev);
+
+/* video parser functions */
+u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size,
+ u32 *p_bytes_used);
+u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
+ u32 *p_bytes_used);
+int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_buffer, u32 bytes_to_copy);
+void cx231xx_reset_video_buffer(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q);
+u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q);
+u32 cx231xx_copy_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_line, u32 length, int field_number);
+u32 cx231xx_get_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 sav_eav, u8 *p_buffer, u32 buffer_size);
+void cx231xx_swab(u16 *from, u16 *to, u16 len);
+
+/* Provided by cx231xx-core.c */
+
+u32 cx231xx_request_buffers(struct cx231xx *dev, u32 count);
+void cx231xx_queue_unusedframes(struct cx231xx *dev);
+void cx231xx_release_buffers(struct cx231xx *dev);
+
+/* read from control pipe */
+int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+
+/* write to control pipe */
+int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode);
+
+int cx231xx_send_vendor_cmd(struct cx231xx *dev,
+ struct VENDOR_REQUEST_IN *ven_req);
+int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
+ struct cx231xx_i2c_xfer_data *req_data);
+
+/* Gpio related functions */
+int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
+ u8 len, u8 request, u8 direction);
+int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
+int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
+int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value);
+int cx231xx_set_gpio_direction(struct cx231xx *dev, int pin_number,
+ int pin_value);
+
+int cx231xx_gpio_i2c_start(struct cx231xx *dev);
+int cx231xx_gpio_i2c_end(struct cx231xx *dev);
+int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data);
+int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf);
+int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev);
+int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev);
+int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev);
+
+int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len);
+int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len);
+
+/* audio related functions */
+int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
+ enum AUDIO_INPUT audio_input);
+
+int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type);
+int cx231xx_resolution_set(struct cx231xx *dev);
+int cx231xx_set_video_alternate(struct cx231xx *dev);
+int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt);
+int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct cx231xx *dev,
+ struct urb *urb));
+void cx231xx_uninit_isoc(struct cx231xx *dev);
+int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode);
+int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio);
+
+/* Device list functions */
+void cx231xx_release_resources(struct cx231xx *dev);
+void cx231xx_release_analog_resources(struct cx231xx *dev);
+int cx231xx_register_analog_devices(struct cx231xx *dev);
+void cx231xx_remove_from_devlist(struct cx231xx *dev);
+void cx231xx_add_into_devlist(struct cx231xx *dev);
+struct cx231xx *cx231xx_get_device(int minor,
+ enum v4l2_buf_type *fh_type, int *has_radio);
+void cx231xx_init_extension(struct cx231xx *dev);
+void cx231xx_close_extension(struct cx231xx *dev);
+
+/* hardware init functions */
+int cx231xx_dev_init(struct cx231xx *dev);
+void cx231xx_dev_uninit(struct cx231xx *dev);
+void cx231xx_config_i2c(struct cx231xx *dev);
+int cx231xx_config(struct cx231xx *dev);
+
+/* Stream control functions */
+int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask);
+int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask);
+
+int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type);
+
+/* Power control functions */
+int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode);
+int cx231xx_power_suspend(struct cx231xx *dev);
+
+/* chip specific control functions */
+int cx231xx_init_ctrl_pin_status(struct cx231xx *dev);
+int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
+ u8 analog_or_digital);
+int cx231xx_enable_i2c_for_tuner(struct cx231xx *dev, u8 I2CIndex);
+
+/* video audio decoder related functions */
+void video_mux(struct cx231xx *dev, int index);
+int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input);
+int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input);
+int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev);
+int cx231xx_set_audio_input(struct cx231xx *dev, u8 input);
+void get_scale(struct cx231xx *dev,
+ unsigned int width, unsigned int height,
+ unsigned int *hscale, unsigned int *vscale);
+
+/* Provided by cx231xx-video.c */
+int cx231xx_register_extension(struct cx231xx_ops *dev);
+void cx231xx_unregister_extension(struct cx231xx_ops *dev);
+void cx231xx_init_extension(struct cx231xx *dev);
+void cx231xx_close_extension(struct cx231xx *dev);
+
+/* Provided by cx231xx-cards.c */
+extern void cx231xx_pre_card_setup(struct cx231xx *dev);
+extern void cx231xx_card_setup(struct cx231xx *dev);
+extern struct cx231xx_board cx231xx_boards[];
+extern struct usb_device_id cx231xx_id_table[];
+extern const unsigned int cx231xx_bcount;
+void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir);
+int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
+
+/* Provided by cx231xx-input.c */
+int cx231xx_ir_init(struct cx231xx *dev);
+int cx231xx_ir_fini(struct cx231xx *dev);
+
+/* printk macros */
+
+#define cx231xx_err(fmt, arg...) do {\
+ printk(KERN_ERR fmt , ##arg); } while (0)
+
+#define cx231xx_errdev(fmt, arg...) do {\
+ printk(KERN_ERR "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+
+#define cx231xx_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+#define cx231xx_warn(fmt, arg...) do {\
+ printk(KERN_WARNING "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+
+static inline unsigned int norm_maxw(struct cx231xx *dev)
+{
+ if (dev->board.max_range_640_480)
+ return 640;
+ else
+ return 720;
+}
+
+static inline unsigned int norm_maxh(struct cx231xx *dev)
+{
+ if (dev->board.max_range_640_480)
+ return 480;
+ else
+ return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
+}
+#endif
diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig
index 00f1e2e88..fd3fc3e31 100644
--- a/linux/drivers/media/video/cx23885/Kconfig
+++ b/linux/drivers/media/video/cx23885/Kconfig
@@ -15,12 +15,15 @@ config VIDEO_CX23885
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE
- select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_STV6110 if !DVB_FE_CUSTOMISE
+ select DVB_STV0900 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
---help---
This is a video4linux driver for Conexant 23885 based
TV cards.
diff --git a/linux/drivers/media/video/cx23885/Makefile b/linux/drivers/media/video/cx23885/Makefile
index 29c23b44c..ab8ea35c9 100644
--- a/linux/drivers/media/video/cx23885/Makefile
+++ b/linux/drivers/media/video/cx23885/Makefile
@@ -1,4 +1,6 @@
-cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
+cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
+ cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
+ netup-init.o cimax2.o netup-eeprom.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
diff --git a/linux/drivers/media/video/cx23885/cimax2.c b/linux/drivers/media/video/cx23885/cimax2.c
new file mode 100644
index 000000000..0e29f97f3
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/cimax2.c
@@ -0,0 +1,484 @@
+/*
+ * cimax2.c
+ *
+ * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx23885.h"
+#include "dvb_ca_en50221.h"
+/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
+ bits 31-16
++-----------+
+| Reserved |
++-----------+
+ bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+| WR# | RD# | | ACK# | ADHI | ADLO | CS1# | CS0# |
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+| DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+/* MC417 */
+#define NETUP_DATA 0x000000ff
+#define NETUP_WR 0x00008000
+#define NETUP_RD 0x00004000
+#define NETUP_ACK 0x00001000
+#define NETUP_ADHI 0x00000800
+#define NETUP_ADLO 0x00000400
+#define NETUP_CS1 0x00000200
+#define NETUP_CS0 0x00000100
+#define NETUP_EN_ALL 0x00001000
+#define NETUP_CTRL_OFF (NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD)
+#define NETUP_CI_CTL 0x04
+#define NETUP_CI_RD 1
+
+
+static unsigned int ci_dbg;
+module_param(ci_dbg, int, 0644);
+MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
+
+#define ci_dbg_print(args...) \
+ do { \
+ if (ci_dbg) \
+ printk(KERN_DEBUG args); \
+ } while (0)
+
+/* stores all private variables for communication with CI */
+struct netup_ci_state {
+ struct dvb_ca_en50221 ca;
+ struct mutex ca_mutex;
+ struct i2c_adapter *i2c_adap;
+ u8 ci_i2c_addr;
+ int status;
+ struct work_struct work;
+ void *priv;
+};
+
+struct mutex gpio_mutex;/* Two CiMax's uses same GPIO lines */
+
+int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+ u8 *buf, int len)
+{
+ int ret;
+ struct i2c_msg msg[] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .buf = &reg,
+ .len = 1
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .buf = buf,
+ .len = len
+ }
+ };
+
+ ret = i2c_transfer(i2c_adap, msg, 2);
+
+ if (ret != 2) {
+ ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n",
+ __func__, reg, ret);
+
+ return -1;
+ }
+
+ ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n",
+ __func__, addr, reg, buf[0]);
+
+ return 0;
+}
+
+int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+ u8 *buf, int len)
+{
+ int ret;
+ u8 buffer[len + 1];
+
+ struct i2c_msg msg = {
+ .addr = addr,
+ .flags = 0,
+ .buf = &buffer[0],
+ .len = len + 1
+ };
+
+ buffer[0] = reg;
+ memcpy(&buffer[1], buf, len);
+
+ ret = i2c_transfer(i2c_adap, &msg, 1);
+
+ if (ret != 1) {
+ ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n",
+ __func__, reg, ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int netup_ci_get_mem(struct cx23885_dev *dev)
+{
+ int mem;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+ for (;;) {
+ mem = cx_read(MC417_RWD);
+ if ((mem & NETUP_ACK) == 0)
+ break;
+ if (time_after(jiffies, timeout))
+ break;
+ udelay(1);
+ }
+
+ cx_set(MC417_RWD, NETUP_CTRL_OFF);
+
+ return mem & 0xff;
+}
+
+int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
+ u8 flag, u8 read, int addr, u8 data)
+{
+ struct netup_ci_state *state = en50221->data;
+ struct cx23885_tsport *port = state->priv;
+ struct cx23885_dev *dev = port->dev;
+
+ u8 store;
+ int mem;
+ int ret;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &store, 1);
+ if (ret != 0)
+ return ret;
+
+ store &= ~0x0c;
+ store |= flag;
+
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &store, 1);
+ if (ret != 0)
+ return ret;
+
+ mutex_lock(&gpio_mutex);
+
+ /* write addr */
+ cx_write(MC417_OEN, NETUP_EN_ALL);
+ cx_write(MC417_RWD, NETUP_CTRL_OFF |
+ NETUP_ADLO | (0xff & addr));
+ cx_clear(MC417_RWD, NETUP_ADLO);
+ cx_write(MC417_RWD, NETUP_CTRL_OFF |
+ NETUP_ADHI | (0xff & (addr >> 8)));
+ cx_clear(MC417_RWD, NETUP_ADHI);
+
+ if (read) /* data in */
+ cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
+ else /* data out */
+ cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
+
+ /* choose chip */
+ cx_clear(MC417_RWD,
+ (state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1);
+ /* read/write */
+ cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR);
+ mem = netup_ci_get_mem(dev);
+
+ mutex_unlock(&gpio_mutex);
+
+ if (!read)
+ if (mem < 0)
+ return -EREMOTEIO;
+
+ ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
+ (read) ? "read" : "write", addr,
+ (flag == NETUP_CI_CTL) ? "ctl" : "mem",
+ (read) ? mem : data);
+
+ if (read)
+ return mem;
+
+ return 0;
+}
+
+int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr)
+{
+ return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr, u8 data)
+{
+ return netup_ci_op_cam(en50221, slot, 0, 0, addr, data);
+}
+
+int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+ return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL,
+ NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
+ u8 addr, u8 data)
+{
+ return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data);
+}
+
+int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct netup_ci_state *state = en50221->data;
+ u8 buf = 0x80;
+ int ret;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ udelay(500);
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf, 1);
+
+ if (ret != 0)
+ return ret;
+
+ udelay(500);
+
+ buf = 0x00;
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf, 1);
+
+ msleep(1000);
+ dvb_ca_en50221_camready_irq(&state->ca, 0);
+
+ return 0;
+
+}
+
+int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+ /* not implemented */
+ return 0;
+}
+
+int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct netup_ci_state *state = en50221->data;
+ u8 buf = 0x60;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf, 1);
+}
+
+/* work handler */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void netup_read_ci_status(void *_state)
+#else
+static void netup_read_ci_status(struct work_struct *work)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ struct netup_ci_state *state = _state;
+#else
+ struct netup_ci_state *state =
+ container_of(work, struct netup_ci_state, work);
+#endif
+ u8 buf[33];
+ int ret;
+
+ ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf[0], 33);
+
+ if (ret != 0)
+ return;
+
+ ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, "
+ "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0],
+ buf[32]);
+
+ if (buf[0] && 1)
+ state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+ else
+ state->status = 0;
+}
+
+/* CI irq handler */
+int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status)
+{
+ struct cx23885_tsport *port = NULL;
+ struct netup_ci_state *state = NULL;
+
+ if (pci_status & PCI_MSK_GPIO0)
+ port = &dev->ts1;
+ else if (pci_status & PCI_MSK_GPIO1)
+ port = &dev->ts2;
+ else /* who calls ? */
+ return 0;
+
+ state = port->port_priv;
+
+ schedule_work(&state->work);
+
+ return 1;
+}
+
+int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+ struct netup_ci_state *state = en50221->data;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ return state->status;
+}
+
+int netup_ci_init(struct cx23885_tsport *port)
+{
+ struct netup_ci_state *state;
+ u8 cimax_init[34] = {
+ 0x00, /* module A control*/
+ 0x00, /* auto select mask high A */
+ 0x00, /* auto select mask low A */
+ 0x00, /* auto select pattern high A */
+ 0x00, /* auto select pattern low A */
+ 0x44, /* memory access time A */
+ 0x00, /* invert input A */
+ 0x00, /* RFU */
+ 0x00, /* RFU */
+ 0x00, /* module B control*/
+ 0x00, /* auto select mask high B */
+ 0x00, /* auto select mask low B */
+ 0x00, /* auto select pattern high B */
+ 0x00, /* auto select pattern low B */
+ 0x44, /* memory access time B */
+ 0x00, /* invert input B */
+ 0x00, /* RFU */
+ 0x00, /* RFU */
+ 0x00, /* auto select mask high Ext */
+ 0x00, /* auto select mask low Ext */
+ 0x00, /* auto select pattern high Ext */
+ 0x00, /* auto select pattern low Ext */
+ 0x00, /* RFU */
+ 0x02, /* destination - module A */
+ 0x01, /* power on (use it like store place) */
+ 0x00, /* RFU */
+ 0x00, /* int status read only */
+ 0x01, /* all int unmasked */
+ 0x04, /* int config */
+ 0x00, /* USCG1 */
+ 0x04, /* ack active low */
+ 0x00, /* LOCK = 0 */
+ 0x33, /* serial mode, rising in, rising out, MSB first*/
+ 0x31, /* syncronization */
+ };
+ int ret;
+
+ ci_dbg_print("%s\n", __func__);
+ state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL);
+ if (!state) {
+ ci_dbg_print("%s: Unable create CI structure!\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ port->port_priv = state;
+
+ switch (port->nr) {
+ case 1:
+ state->ci_i2c_addr = 0x40;
+ mutex_init(&gpio_mutex);
+ break;
+ case 2:
+ state->ci_i2c_addr = 0x41;
+ break;
+ }
+
+ state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap;
+ state->ca.owner = THIS_MODULE;
+ state->ca.read_attribute_mem = netup_ci_read_attribute_mem;
+ state->ca.write_attribute_mem = netup_ci_write_attribute_mem;
+ state->ca.read_cam_control = netup_ci_read_cam_ctl;
+ state->ca.write_cam_control = netup_ci_write_cam_ctl;
+ state->ca.slot_reset = netup_ci_slot_reset;
+ state->ca.slot_shutdown = netup_ci_slot_shutdown;
+ state->ca.slot_ts_enable = netup_ci_slot_ts_ctl;
+ state->ca.poll_slot_status = netup_poll_ci_slot_status;
+ state->ca.data = state;
+ state->priv = port;
+
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &cimax_init[0], 34);
+ /* lock registers */
+ ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0x1f, &cimax_init[0x18], 1);
+ /* power on slots */
+ ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0x18, &cimax_init[0x18], 1);
+
+ if (0 != ret)
+ goto err;
+
+ ret = dvb_ca_en50221_init(&port->frontends.adapter,
+ &state->ca,
+ /* flags */ 0,
+ /* n_slots */ 1);
+ if (0 != ret)
+ goto err;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&state->work, netup_read_ci_status, state);
+#else
+ INIT_WORK(&state->work, netup_read_ci_status);
+#endif
+
+ ci_dbg_print("%s: CI initialized!\n", __func__);
+
+ return 0;
+err:
+ ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
+ kfree(state);
+ return ret;
+}
+
+void netup_ci_exit(struct cx23885_tsport *port)
+{
+ struct netup_ci_state *state;
+
+ if (NULL == port)
+ return;
+
+ state = (struct netup_ci_state *)port->port_priv;
+ if (NULL == state)
+ return;
+
+ if (NULL == state->ca.data)
+ return;
+
+ dvb_ca_en50221_release(&state->ca);
+ kfree(state);
+}
diff --git a/linux/drivers/media/video/cx23885/cimax2.h b/linux/drivers/media/video/cx23885/cimax2.h
new file mode 100644
index 000000000..518744a4c
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/cimax2.h
@@ -0,0 +1,47 @@
+/*
+ * cimax2.h
+ *
+ * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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.
+ */
+
+#ifndef CIMAX2_H
+#define CIMAX2_H
+#include "dvb_ca_en50221.h"
+
+extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr);
+extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr, u8 data);
+extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221,
+ int slot, u8 addr);
+extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221,
+ int slot, u8 addr, u8 data);
+extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status);
+extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221,
+ int slot, int open);
+extern int netup_ci_init(struct cx23885_tsport *port);
+extern void netup_ci_exit(struct cx23885_tsport *port);
+
+#endif
diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c
index 0766a97a0..7e7e75237 100644
--- a/linux/drivers/media/video/cx23885/cx23885-417.c
+++ b/linux/drivers/media/video/cx23885/cx23885-417.c
@@ -1206,21 +1206,16 @@ static int vidioc_enum_input(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
struct cx23885_input *input;
- unsigned int n;
+ int n;
- n = i->index;
-
- if (n >= 4)
+ if (i->index >= 4)
return -EINVAL;
- input = &cx23885_boards[dev->board].input[n];
+ input = &cx23885_boards[dev->board].input[i->index];
if (input->type == 0)
return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = n;
-
/* FIXME
* strcpy(i->name, input->name); */
strcpy(i->name, "unset");
@@ -1263,7 +1258,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
return -EINVAL;
if (0 != t->index)
return -EINVAL;
- memset(t, 0, sizeof(*t));
strcpy(t->name, "Television");
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
@@ -1294,7 +1288,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- memset(f, 0, sizeof(*f));
if (UNSET == dev->tuner_type)
return -EINVAL;
f->type = V4L2_TUNER_ANALOG_TV;
@@ -1354,7 +1347,6 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx23885_dev *dev = fh->dev;
struct cx23885_tsport *tsport = &dev->ts1;
- memset(cap, 0, sizeof(*cap));
strcpy(cap->driver, dev->name);
strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
sizeof(cap->card));
@@ -1374,16 +1366,10 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- int index;
-
- index = f->index;
- if (index != 0)
+ if (f->index != 0)
return -EINVAL;
- memset(f, 0, sizeof(*f));
- f->index = index;
strlcpy(f->description, "MPEG", sizeof(f->description));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->pixelformat = V4L2_PIX_FMT_MPEG;
return 0;
@@ -1395,8 +1381,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- memset(f, 0, sizeof(*f));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage =
@@ -1416,12 +1400,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage =
dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.sizeimage =
f->fmt.pix.colorspace = 0;
dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
dev->ts1.width, dev->ts1.height, fh->mpegq.field);
@@ -1434,7 +1416,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage =
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index a8201ceaa..e6db78f8b 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -28,6 +28,7 @@
#include "compat.h"
#include "cx23885.h"
#include "tuner-xc2028.h"
+#include "netup-init.h"
/* ------------------------------------------------------------------ */
/* board config info */
@@ -175,6 +176,12 @@ struct cx23885_board cx23885_boards[] = {
.name = "DVBWorld DVB-S2 2005",
.portb = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
+ .cimax = 1,
+ .name = "NetUP Dual DVB-S2 CI",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -270,6 +277,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0001,
.subdevice = 0x2005,
.card = CX23885_BOARD_DVBWORLD_2005,
+ }, {
+ .subvendor = 0x1b55,
+ .subdevice = 0x2a2c,
+ .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -583,6 +594,32 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_write(MC417_OEN, 0x00001000);
cx_write(MC417_RWD, 0x00001800);
break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ /* GPIO-0 INTA from CiMax1
+ GPIO-1 INTB from CiMax2
+ GPIO-2 reset chips
+ GPIO-3 to GPIO-10 data/addr for CA
+ GPIO-11 ~CS0 to CiMax1
+ GPIO-12 ~CS1 to CiMax2
+ GPIO-13 ADL0 load LSB addr
+ GPIO-14 ADL1 load MSB addr
+ GPIO-15 ~RDY from CiMax
+ GPIO-17 ~RD to CiMax
+ GPIO-18 ~WR to CiMax
+ */
+ cx_set(GP0_IO, 0x00040000); /* GPIO as out */
+ /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
+ cx_clear(GP0_IO, 0x00030004);
+ mdelay(100);/* reset delay */
+ cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
+ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+ /* GPIO-15 IN as ~ACK, rest as OUT */
+ cx_write(MC417_OEN, 0x00001000);
+ /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
+ cx_write(MC417_RWD, 0x0000c300);
+ /* enable irq */
+ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+ break;
}
}
@@ -670,6 +707,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -694,9 +739,17 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
request_module("cx25840");
break;
}
+
+ /* AUX-PLL 27MHz CLK */
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ netup_initialize(dev);
+ break;
+ }
}
/* ------------------------------------------------------------------ */
diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c
index 4f68156d2..d894d4900 100644
--- a/linux/drivers/media/video/cx23885/cx23885-core.c
+++ b/linux/drivers/media/video/cx23885/cx23885-core.c
@@ -32,6 +32,7 @@
#include <asm/div64.h>
#include "cx23885.h"
+#include "cimax2.h"
MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -792,6 +793,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dev->pci_bus = dev->pci->bus->number;
dev->pci_slot = PCI_SLOT(dev->pci->devfn);
dev->pci_irqmask = 0x001f00;
+ if (cx23885_boards[dev->board].cimax > 0)
+ dev->pci_irqmask |= 0x01800000; /* for CiMaxes */
/* External Master 1 Bus */
dev->i2c_bus[0].nr = 0;
@@ -1654,7 +1657,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
(pci_status & PCI_MSK_VID_B) ||
(pci_status & PCI_MSK_VID_A) ||
(pci_status & PCI_MSK_AUD_INT) ||
- (pci_status & PCI_MSK_AUD_EXT)) {
+ (pci_status & PCI_MSK_AUD_EXT) ||
+ (pci_status & PCI_MSK_GPIO0) ||
+ (pci_status & PCI_MSK_GPIO1)) {
if (pci_status & PCI_MSK_RISC_RD)
dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
@@ -1696,8 +1701,20 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n",
PCI_MSK_AUD_EXT);
+ if (pci_status & PCI_MSK_GPIO0)
+ dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n",
+ PCI_MSK_GPIO0);
+
+ if (pci_status & PCI_MSK_GPIO1)
+ dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
+ PCI_MSK_GPIO1);
}
+ if (cx23885_boards[dev->board].cimax > 0 &&
+ ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1)))
+ /* handled += cx23885_irq_gpio(dev, pci_status); */
+ handled += netup_ci_slot_status(dev, pci_status);
+
if (ts1_status) {
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts1, ts1_status);
@@ -1770,6 +1787,13 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
}
pci_set_drvdata(pci_dev, dev);
+
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ cx_set(PCI_INT_MSK, 0x01800000); /* for NetUP */
+ break;
+ }
+
return 0;
fail_irq:
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 90dbf49ea..364543987 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -31,6 +31,7 @@
#include "cx23885.h"
#include <media/v4l2-common.h>
+#include "dvb_ca_en50221.h"
#include "s5h1409.h"
#include "s5h1411.h"
#include "mt2131.h"
@@ -44,7 +45,13 @@
#include "dib7000p.h"
#include "dibx000_common.h"
#include "zl10353.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "lnbh24.h"
#include "cx24116.h"
+#include "cimax2.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
static unsigned int debug;
@@ -310,6 +317,31 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = {
.no_tuner = 1,
};
+static struct stv0900_config netup_stv0900_config = {
+ .demod_address = 0x68,
+ .xtal = 27000000,
+ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+ .diseqc_mode = 2,/* 2/3 PWM */
+ .path1_mode = 2,/*Serial continues clock */
+ .path2_mode = 2,/*Serial continues clock */
+ .tun1_maddress = 0,/* 0x60 */
+ .tun2_maddress = 3,/* 0x63 */
+ .tun1_adc = 1,/* 1 Vpp */
+ .tun2_adc = 1,/* 1 Vpp */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_a = {
+ .i2c_address = 0x60,
+ .mclk = 27000000,
+ .iq_wiring = 0,
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_b = {
+ .i2c_address = 0x63,
+ .mclk = 27000000,
+ .iq_wiring = 1,
+};
+
static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct cx23885_tsport *port = fe->dvb->priv;
@@ -341,6 +373,7 @@ static int dvb_register(struct cx23885_tsport *port)
struct cx23885_dev *dev = port->dev;
struct cx23885_i2c *i2c_bus = NULL;
struct videobuf_dvb_frontend *fe0;
+ int ret;
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
@@ -581,6 +614,51 @@ static int dvb_register(struct cx23885_tsport *port)
&dvbworld_cx24116_config,
&i2c_bus->i2c_adap);
break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ i2c_bus = &dev->i2c_bus[0];
+ switch (port->nr) {
+ /* port B */
+ case 1:
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
+ &netup_stv0900_config,
+ &i2c_bus->i2c_adap, 0);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(stv6110_attach,
+ fe0->dvb.frontend,
+ &netup_stv6110_tunerconfig_a,
+ &i2c_bus->i2c_adap)) {
+ if (!dvb_attach(lnbh24_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ LNBH24_PCL, 0, 0x09))
+ printk(KERN_ERR
+ "No LNBH24 found!\n");
+
+ }
+ }
+ break;
+ /* port C */
+ case 2:
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
+ &netup_stv0900_config,
+ &i2c_bus->i2c_adap, 1);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(stv6110_attach,
+ fe0->dvb.frontend,
+ &netup_stv6110_tunerconfig_b,
+ &i2c_bus->i2c_adap)) {
+ if (!dvb_attach(lnbh24_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ LNBH24_PCL, 0, 0x0a))
+ printk(KERN_ERR
+ "No LNBH24 found!\n");
+
+ }
+ }
+ break;
+ }
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
@@ -602,9 +680,33 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
/* register everything */
- return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr, 0);
+ /* init CI & MAC */
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+ static struct netup_card_info cinfo;
+
+ netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+ memcpy(port->frontends.adapter.proposed_mac,
+ cinfo.port[port->nr - 1].mac, 6);
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC="
+ "%02X:%02X:%02X:%02X:%02X:%02X\n",
+ port->nr,
+ port->frontends.adapter.proposed_mac[0],
+ port->frontends.adapter.proposed_mac[1],
+ port->frontends.adapter.proposed_mac[2],
+ port->frontends.adapter.proposed_mac[3],
+ port->frontends.adapter.proposed_mac[4],
+ port->frontends.adapter.proposed_mac[5]);
+
+ netup_ci_init(port);
+ break;
+ }
+ }
+
+ return ret;
}
int cx23885_dvb_register(struct cx23885_tsport *port)
@@ -677,6 +779,12 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
if (fe0->dvb.frontend)
videobuf_dvb_unregister_bus(&port->frontends);
+ switch (port->dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ netup_ci_exit(port);
+ break;
+ }
+
return 0;
}
diff --git a/linux/drivers/media/video/cx23885/cx23885-reg.h b/linux/drivers/media/video/cx23885/cx23885-reg.h
index 20b68a236..eafbe5226 100644
--- a/linux/drivers/media/video/cx23885/cx23885-reg.h
+++ b/linux/drivers/media/video/cx23885/cx23885-reg.h
@@ -212,6 +212,8 @@ Channel manager Data Structure entry = 20 DWORD
#define DEV_CNTRL2 0x00040000
+#define PCI_MSK_GPIO1 (1 << 24)
+#define PCI_MSK_GPIO0 (1 << 23)
#define PCI_MSK_APB_DMA (1 << 12)
#define PCI_MSK_AL_WR (1 << 11)
#define PCI_MSK_AL_RD (1 << 10)
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index 131fc740a..ba22520a2 100644
--- a/linux/drivers/media/video/cx23885/cx23885-video.c
+++ b/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -36,11 +36,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
-
MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index cae0a74bd..e8118c6bd 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -71,6 +71,7 @@
#define CX23885_BOARD_TBS_6920 14
#define CX23885_BOARD_TEVII_S470 15
#define CX23885_BOARD_DVBWORLD_2005 16
+#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
@@ -188,6 +189,7 @@ struct cx23885_board {
*/
u32 clk_freq;
struct cx23885_input input[MAX_CX23885_INPUT];
+ int cimax; /* for NetUP */
};
struct cx23885_subid {
@@ -270,6 +272,7 @@ struct cx23885_tsport {
/* Allow a single tsport to have multiple frontends */
u32 num_frontends;
+ void *port_priv;
};
struct cx23885_dev {
diff --git a/linux/drivers/media/video/cx23885/netup-eeprom.c b/linux/drivers/media/video/cx23885/netup-eeprom.c
new file mode 100644
index 000000000..26b934cd7
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-eeprom.c
@@ -0,0 +1,117 @@
+
+/*
+ * netup-eeprom.c
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#
+#include "cx23885.h"
+#include "netup-eeprom.h"
+
+#define EEPROM_I2C_ADDR 0x50
+
+int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr)
+{
+ int ret;
+ unsigned char buf[2];
+
+ /* Read from EEPROM */
+ struct i2c_msg msg[] = {
+ {
+ .addr = EEPROM_I2C_ADDR,
+ .flags = 0,
+ .buf = &buf[0],
+ .len = 1
+ }, {
+ .addr = EEPROM_I2C_ADDR,
+ .flags = I2C_M_RD,
+ .buf = &buf[1],
+ .len = 1
+ }
+
+ };
+
+ buf[0] = addr;
+ buf[1] = 0x0;
+
+ ret = i2c_transfer(i2c_adap, msg, 2);
+
+ if (ret != 2) {
+ printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret);
+ return -1;
+ }
+
+ return buf[1];
+};
+
+int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data)
+{
+ int ret;
+ unsigned char bufw[2];
+
+ /* Write into EEPROM */
+ struct i2c_msg msg[] = {
+ {
+ .addr = EEPROM_I2C_ADDR,
+ .flags = 0,
+ .buf = &bufw[0],
+ .len = 2
+ }
+ };
+
+ bufw[0] = addr;
+ bufw[1] = data;
+
+ ret = i2c_transfer(i2c_adap, msg, 1);
+
+ if (ret != 1) {
+ printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret);
+ return -1;
+ }
+
+ mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */
+ return 0;
+};
+
+void netup_get_card_info(struct i2c_adapter *i2c_adap,
+ struct netup_card_info *cinfo)
+{
+ int i, j;
+
+ cinfo->rev = netup_eeprom_read(i2c_adap, 13);
+
+ for (i = 0, j = 0; i < 6; i++, j++)
+ cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i);
+
+ for (i = 6, j = 0; i < 12; i++, j++)
+ cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i);
+#if 0
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card rev=0x%x MAC1=%02X:%02X:"
+ "%02X:%02X:%02X:%02X MAC2=%02X:%02X:%02X:%02X:%02X:%02X\n", cinfo->rev,
+ cinfo->port[0].mac[0], cinfo->port[0].mac[1],
+ cinfo->port[0].mac[2], cinfo->port[0].mac[3],
+ cinfo->port[0].mac[4], cinfo->port[0].mac[5],
+ cinfo->port[1].mac[0], cinfo->port[1].mac[1],
+ cinfo->port[1].mac[2], cinfo->port[1].mac[3],
+ cinfo->port[1].mac[4], cinfo->port[1].mac[5]);
+#endif
+};
diff --git a/linux/drivers/media/video/cx23885/netup-eeprom.h b/linux/drivers/media/video/cx23885/netup-eeprom.h
new file mode 100644
index 000000000..13926e18f
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-eeprom.h
@@ -0,0 +1,42 @@
+/*
+ * netup-eeprom.h
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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.
+ */
+
+#ifndef NETUP_EEPROM_H
+#define NETUP_EEPROM_H
+
+struct netup_port_info {
+ u8 mac[6];/* card MAC address */
+};
+
+struct netup_card_info {
+ struct netup_port_info port[2];/* ports - 1,2 */
+ u8 rev;/* card revision */
+};
+
+extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr);
+extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data);
+extern void netup_get_card_info(struct i2c_adapter *i2c_adap,
+ struct netup_card_info *cinfo);
+
+#endif
diff --git a/linux/drivers/media/video/cx23885/netup-init.c b/linux/drivers/media/video/cx23885/netup-init.c
new file mode 100644
index 000000000..f4893e69c
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-init.c
@@ -0,0 +1,125 @@
+/*
+ * netup-init.c
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx23885.h"
+
+static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val)
+{
+ int ret;
+ u8 buf[3];
+ struct i2c_msg msg = {
+ .addr = 0x88 >> 1,
+ .flags = 0,
+ .buf = buf,
+ .len = 3
+ };
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ buf[2] = val;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val)
+{
+ int ret;
+ u8 buf[6];
+ struct i2c_msg msg = {
+ .addr = 0x88 >> 1,
+ .flags = 0,
+ .buf = buf,
+ .len = 6
+ };
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ buf[2] = val & 0xff;
+ buf[3] = (val >> 8) & 0xff;
+ buf[4] = (val >> 16) & 0xff;
+ buf[5] = val >> 24;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg)
+{
+ int ret;
+ u8 buf[2];
+ struct i2c_msg msg = {
+ .addr = 0x88 >> 1,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c write error!\n", __func__);
+
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c read error!\n", __func__);
+
+ return buf[0];
+}
+
+static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask,
+ u8 or_value)
+{
+ i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value);
+}
+/* set 27MHz on AUX_CLK */
+void netup_initialize(struct cx23885_dev *dev)
+{
+ struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2];
+ struct i2c_adapter *i2c = &i2c_bus->i2c_adap;
+
+ /* Stop microcontroller */
+ i2c_av_and_or(i2c, 0x803, ~0x10, 0x00);
+
+ /* Aux PLL frac for 27 MHz */
+ i2c_av_write4(i2c, 0x114, 0xea0eb3);
+
+ /* Aux PLL int for 27 MHz */
+ i2c_av_write4(i2c, 0x110, 0x090319);
+
+ /* start microcontroller */
+ i2c_av_and_or(i2c, 0x803, ~0x10, 0x10);
+}
diff --git a/linux/drivers/media/video/cx23885/netup-init.h b/linux/drivers/media/video/cx23885/netup-init.h
new file mode 100644
index 000000000..d26ae4b15
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-init.h
@@ -0,0 +1,25 @@
+/*
+ * netup-init.h
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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.
+ */
+extern void netup_initialize(struct cx23885_dev *dev);
diff --git a/linux/drivers/media/video/cx25840/cx25840-audio.c b/linux/drivers/media/video/cx25840/cx25840-audio.c
index 3ee7d7a7d..9dcdef03e 100644
--- a/linux/drivers/media/video/cx25840/cx25840-audio.c
+++ b/linux/drivers/media/video/cx25840/cx25840-audio.c
@@ -33,7 +33,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* common for all inputs and rates */
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
- if (!state->is_cx23885)
+ if (!state->is_cx23885 && !state->is_cx231xx)
cx25840_write(client, 0x127, 0x50);
if (state->aud_input != CX25840_AUDIO_SERIAL) {
@@ -44,11 +44,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
* so avoid destroying registers. */
break;
}
- /* VID_PLL and AUX_PLL */
- cx25840_write4(client, 0x108, 0x1006040f);
- /* AUX_PLL_FRAC */
- cx25840_write4(client, 0x110, 0x01bb39ee);
+ if (!state->is_cx231xx) {
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x1006040f);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0x01bb39ee);
+ }
if (state->is_cx25836)
break;
@@ -65,11 +68,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
* so avoid destroying registers. */
break;
}
- /* VID_PLL and AUX_PLL */
- cx25840_write4(client, 0x108, 0x1009040f);
- /* AUX_PLL_FRAC */
- cx25840_write4(client, 0x110, 0x00ec6bd6);
+ if (!state->is_cx231xx) {
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x1009040f);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0x00ec6bd6);
+ }
if (state->is_cx25836)
break;
@@ -86,11 +92,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
* so avoid destroying registers. */
break;
}
- /* VID_PLL and AUX_PLL */
- cx25840_write4(client, 0x108, 0x100a040f);
- /* AUX_PLL_FRAC */
- cx25840_write4(client, 0x110, 0x0098d6e5);
+ if (!state->is_cx231xx) {
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x100a040f);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0x0098d6e5);
+ }
if (state->is_cx25836)
break;
@@ -109,11 +118,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
* so avoid destroying registers. */
break;
}
- /* VID_PLL and AUX_PLL */
- cx25840_write4(client, 0x108, 0x1e08040f);
- /* AUX_PLL_FRAC */
- cx25840_write4(client, 0x110, 0x012a0869);
+ if (!state->is_cx231xx) {
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x1e08040f);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0x012a0869);
+ }
if (state->is_cx25836)
break;
@@ -137,11 +149,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
break;
}
- /* VID_PLL and AUX_PLL */
- cx25840_write4(client, 0x108, 0x1809040f);
- /* AUX_PLL_FRAC */
- cx25840_write4(client, 0x110, 0x00ec6bd6);
+ if (!state->is_cx231xx) {
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x1809040f);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0x00ec6bd6);
+ }
if (state->is_cx25836)
break;
@@ -156,7 +171,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
break;
case 48000:
- if (!state->is_cx23885) {
+ if (!state->is_cx23885 && !state->is_cx231xx) {
/* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x180a040f);
@@ -167,7 +182,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
if (state->is_cx25836)
break;
- if (!state->is_cx23885) {
+ if (!state->is_cx23885 && !state->is_cx231xx) {
/* src1_ctl */
cx25840_write4(client, 0x8f8, 0x08018000);
@@ -228,10 +243,9 @@ void cx25840_audio_set_path(struct i2c_client *client)
/* deassert soft reset */
cx25840_and_or(client, 0x810, ~0x1, 0x00);
- if (state->is_cx23885) {
- /* Ensure the controller is running when we exit */
+ /* Ensure the controller is running when we exit */
+ if (state->is_cx23885 || state->is_cx231xx)
cx25840_and_or(client, 0x803, ~0x10, 0x10);
- }
}
static int get_volume(struct i2c_client *client)
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c
index 921cc96fc..5387a846f 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.c
+++ b/linux/drivers/media/video/cx25840/cx25840-core.c
@@ -367,6 +367,85 @@ static void cx23885_initialize(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static void cx231xx_initialize(struct i2c_client *client)
+{
+ DEFINE_WAIT(wait);
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+ struct workqueue_struct *q;
+
+ /* Internal Reset */
+ cx25840_and_or(client, 0x102, ~0x01, 0x01);
+ cx25840_and_or(client, 0x102, ~0x01, 0x00);
+
+ /* Stop microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+
+ /* DIF in reset? */
+ cx25840_write(client, 0x398, 0);
+
+ /* Trust the default xtal, no division */
+ /* This changes for the cx23888 products */
+ cx25840_write(client, 0x2, 0x76);
+
+ /* Bring down the regulator for AUX clk */
+ cx25840_write(client, 0x1, 0x40);
+
+ /* Disable DIF bypass */
+ cx25840_write4(client, 0x33c, 0x00000001);
+
+ /* DIF Src phase inc */
+ cx25840_write4(client, 0x340, 0x0df7df83);
+
+ /* Luma */
+ cx25840_write4(client, 0x414, 0x00107d12);
+
+ /* Chroma */
+ cx25840_write4(client, 0x420, 0x3d008282);
+
+ /* ADC2 input select */
+ cx25840_write(client, 0x102, 0x10);
+
+ /* VIN1 & VIN5 */
+ cx25840_write(client, 0x103, 0x11);
+
+ /* Enable format auto detect */
+ cx25840_write(client, 0x400, 0);
+#if 0
+ /* Force to NTSC-M and Disable autoconf regs */
+ cx25840_write(client, 0x400, 0x21);
+#endif
+ /* Fast subchroma lock */
+ /* White crush, Chroma AGC & Chroma Killer enabled */
+ cx25840_write(client, 0x401, 0xe8);
+
+ /* 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
+ firmware. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&state->fw_work, cx25840_work_handler);
+#else
+ INIT_WORK(&state->fw_work, cx25840_work_handler, state);
+#endif
+ init_waitqueue_head(&state->fw_wait);
+ q = create_singlethread_workqueue("cx25840_fw");
+ prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+ queue_work(q, &state->fw_work);
+ schedule();
+ finish_wait(&state->fw_wait, &wait);
+ destroy_workqueue(q);
+
+ cx25840_std_setup(client);
+
+ /* (re)set input */
+ set_input(client, state->vid_input, state->aud_input);
+
+ /* start microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+}
+
+/* ----------------------------------------------------------------------- */
+
void cx25840_std_setup(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
@@ -436,39 +515,41 @@ void cx25840_std_setup(struct i2c_client *client)
}
/* DEBUG: Displays configured PLL frequency */
- pll_int = cx25840_read(client, 0x108);
- pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
- pll_post = cx25840_read(client, 0x109);
- v4l_dbg(1, cx25840_debug, client,
- "PLL regs = int: %u, frac: %u, post: %u\n",
- pll_int, pll_frac, pll_post);
-
- if (pll_post) {
- int fin, fsc;
- int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
-
- pll /= pll_post;
- v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
- pll / 1000000, pll % 1000000);
- v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
- pll / 8000000, (pll / 8) % 1000000);
-
- fin = ((u64)src_decimation * pll) >> 12;
- v4l_dbg(1, cx25840_debug, client,
- "ADC Sampling freq = %d.%06d MHz\n",
- fin / 1000000, fin % 1000000);
-
- fsc = (((u64)sc) * pll) >> 24L;
+ if (!state->is_cx231xx) {
+ pll_int = cx25840_read(client, 0x108);
+ pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
+ pll_post = cx25840_read(client, 0x109);
v4l_dbg(1, cx25840_debug, client,
- "Chroma sub-carrier freq = %d.%06d MHz\n",
- fsc / 1000000, fsc % 1000000);
-
- v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
- "vblank %i, vactive %i, vblank656 %i, src_dec %i, "
- "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
- "sc 0x%06x\n",
- hblank, hactive, vblank, vactive, vblank656,
- src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ "PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int, pll_frac, pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
+
+ pll /= pll_post;
+ v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+ pll / 1000000, pll % 1000000);
+ v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+ pll / 8000000, (pll / 8) % 1000000);
+
+ fin = ((u64)src_decimation * pll) >> 12;
+ v4l_dbg(1, cx25840_debug, client,
+ "ADC Sampling freq = %d.%06d MHz\n",
+ fin / 1000000, fin % 1000000);
+
+ fsc = (((u64)sc) * pll) >> 24L;
+ v4l_dbg(1, cx25840_debug, client,
+ "Chroma sub-carrier freq = %d.%06d MHz\n",
+ fsc / 1000000, fsc % 1000000);
+
+ v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+ "vblank %i, vactive %i, vblank656 %i, src_dec %i, "
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
+ "sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
}
/* Sets horizontal blanking delay and active lines */
@@ -618,7 +699,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
* configuration in reg (for the cx23885) so we have no
* need to attempt to flip bits for earlier av decoders.
*/
- if (!state->is_cx23885) {
+ if (!state->is_cx23885 && !state->is_cx231xx) {
switch (aud_input) {
case CX25840_AUDIO_SERIAL:
/* do nothing, use serial audio input */
@@ -641,7 +722,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
/* Set INPUT_MODE to Composite (0) or S-Video (1) */
cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
- if (!state->is_cx23885) {
+ if (!state->is_cx23885 && !state->is_cx231xx) {
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
@@ -681,6 +762,19 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
*/
cx25840_write(client, 0x918, 0xa0);
cx25840_write(client, 0x919, 0x01);
+ } else if (state->is_cx231xx) {
+ /* Audio channel 1 src : Parallel 1 */
+ cx25840_write(client, 0x124, 0x03);
+
+ /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
+ cx25840_write(client, 0x914, 0xa0);
+
+ /* I2S_OUT_CTL:
+ * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
+ * I2S_OUT_MASTER_MODE = Master
+ */
+ cx25840_write(client, 0x918, 0xa0);
+ cx25840_write(client, 0x919, 0x01);
}
return 0;
@@ -1142,6 +1236,8 @@ static int cx25840_init(struct v4l2_subdev *sd, u32 val)
cx25836_initialize(client);
else if (state->is_cx23885)
cx23885_initialize(client);
+ else if (state->is_cx231xx)
+ cx231xx_initialize(client);
else
cx25840_initialize(client);
}
@@ -1197,7 +1293,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
v4l_dbg(1, cx25840_debug, client, "%s output\n",
enable ? "enable" : "disable");
if (enable) {
- if (state->is_cx23885) {
+ if (state->is_cx23885 || state->is_cx231xx) {
u8 v = (cx25840_read(client, 0x421) | 0x0b);
cx25840_write(client, 0x421, v);
} else {
@@ -1207,7 +1303,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
state->is_cx25836 ? 0x04 : 0x07);
}
} else {
- if (state->is_cx23885) {
+ if (state->is_cx23885 || state->is_cx231xx) {
u8 v = cx25840_read(client, 0x421) & ~(0x0b);
cx25840_write(client, 0x421, v);
} else {
@@ -1388,6 +1484,8 @@ static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
cx25836_initialize(client);
else if (state->is_cx23885)
cx23885_initialize(client);
+ else if (state->is_cx231xx)
+ cx231xx_initialize(client);
else
cx25840_initialize(client);
return 0;
@@ -1500,6 +1598,8 @@ static int cx25840_probe(struct i2c_client *client,
id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
} else if (device_id == 0x1313) {
id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+ } else if ((device_id & 0xfff0) == 0x5A30) {
+ id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
}
else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
@@ -1522,6 +1622,7 @@ static int cx25840_probe(struct i2c_client *client,
state->c = client;
state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
+ state->is_cx231xx = (device_id == 0x5a3e);
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.h b/linux/drivers/media/video/cx25840/cx25840-core.h
index 0a99c19df..422c63752 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.h
+++ b/linux/drivers/media/video/cx25840/cx25840-core.h
@@ -51,6 +51,7 @@ struct cx25840_state {
u32 rev;
int is_cx25836;
int is_cx23885;
+ int is_cx231xx;
int is_initialized;
wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
struct work_struct fw_work; /* work entry for fw load */
diff --git a/linux/drivers/media/video/cx25840/cx25840-firmware.c b/linux/drivers/media/video/cx25840/cx25840-firmware.c
index 01fbe174e..f01456ec4 100644
--- a/linux/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/linux/drivers/media/video/cx25840/cx25840-firmware.c
@@ -26,6 +26,7 @@
#define FWFILE "v4l-cx25840.fw"
#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
+#define FWFILE_CX231XX "v4l-cx231xx-avcore-01.fw"
/*
* Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
@@ -97,9 +98,17 @@ int cx25840_loadfw(struct i2c_client *client)
u8 buffer[FWSEND];
const u8 *ptr;
int size, retval;
+ int MAX_BUF_SIZE = FWSEND;
if (state->is_cx23885)
firmware = FWFILE_CX23885;
+ else if (state->is_cx231xx)
+ firmware = FWFILE_CX231XX;
+
+ if ((state->is_cx231xx) && MAX_BUF_SIZE > 16) {
+ v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
+ MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */
+ }
if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
v4l_err(client, "unable to open firmware %s\n", firmware);
@@ -114,7 +123,7 @@ int cx25840_loadfw(struct i2c_client *client)
size = fw->size;
ptr = fw->data;
while (size > 0) {
- int len = min(FWSEND - 2, size);
+ int len = min(MAX_BUF_SIZE - 2, size);
memcpy(buffer + 2, ptr, len);
diff --git a/linux/drivers/media/video/cx88/Kconfig b/linux/drivers/media/video/cx88/Kconfig
index 2d250a2a7..49952980d 100644
--- a/linux/drivers/media/video/cx88/Kconfig
+++ b/linux/drivers/media/video/cx88/Kconfig
@@ -61,7 +61,7 @@ config VIDEO_CX88_DVB
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_STV0288 if !DVB_FE_CUSTOMISE
select DVB_STB6000 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
Conexant 2388x chip.
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index f7171586d..1e78faba6 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -657,8 +657,12 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
return changed;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
+#else
+static DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
+#endif
#endif
static struct snd_kcontrol_new snd_cx88_volume = {
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c
index 46e009403..f1a6f6984 100644
--- a/linux/drivers/media/video/cx88/cx88-blackbird.c
+++ b/linux/drivers/media/video/cx88/cx88-blackbird.c
@@ -761,7 +761,6 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
return -EINVAL;
strlcpy(f->description, "MPEG", sizeof(f->description));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->pixelformat = V4L2_PIX_FMT_MPEG;
return 0;
}
@@ -772,7 +771,6 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
struct cx8802_fh *fh = priv;
struct cx8802_dev *dev = fh->dev;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
@@ -791,7 +789,6 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
struct cx8802_fh *fh = priv;
struct cx8802_dev *dev = fh->dev;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
@@ -808,7 +805,6 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
struct cx8802_dev *dev = fh->dev;
struct cx88_core *core = dev->core;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index f9b5a9c09..2f30d34be 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -1967,6 +1967,39 @@ static const struct cx88_board cx88_boards[] = {
} },
.mpeg = CX88_MPEG_DVB,
},
+ [CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII] = {
+ .name = "Terratec Cinergy HT PCI MKII",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .radio_type = TUNER_XC2028,
+ .radio_addr = 0x61,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x004ff,
+ .gpio1 = 0x010ff,
+ .gpio2 = 0x00001,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x004fb,
+ .gpio1 = 0x010ef,
+ .audioroute = 1,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x004fb,
+ .gpio1 = 0x010ef,
+ .audioroute = 1,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x004ff,
+ .gpio1 = 0x010ff,
+ .gpio2 = 0x0ff,
+ },
+ .mpeg = CX88_MPEG_DVB,
+ },
};
/* ------------------------------------------------------------------ */
@@ -2376,6 +2409,10 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0xb200,
.subdevice = 0x4200,
.card = CX88_BOARD_SATTRADE_ST4200,
+ }, {
+ .subvendor = 0x153b,
+ .subdevice = 0x1177,
+ .card = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII,
},
};
@@ -2852,6 +2889,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
*/
break;
case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+ case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
ctl->demod = XC3028_FE_ZARLINK456;
ctl->mts = 1;
break;
@@ -3122,6 +3160,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
int i;
core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (core == NULL)
+ return NULL;
atomic_inc(&core->refcount);
core->pci_bus = pci->bus->number;
@@ -3133,7 +3173,15 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
core->nr = nr;
sprintf(core->name, "cx88[%d]", core->nr);
+
+ strcpy(core->v4l2_dev.name, core->name);
+ if (v4l2_device_register(NULL, &core->v4l2_dev)) {
+ kfree(core);
+ return NULL;
+ }
+
if (0 != cx88_get_resources(core, pci)) {
+ v4l2_device_unregister(&core->v4l2_dev);
kfree(core);
return NULL;
}
@@ -3144,6 +3192,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
pci_resource_len(pci, 0));
core->bmmio = (u8 __iomem *)core->lmmio;
+ if (core->lmmio == NULL) {
+ kfree(core);
+ return NULL;
+ }
+
/* board config */
core->boardnr = UNSET;
if (card[core->nr] < ARRAY_SIZE(cx88_boards))
diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c
index c9de13b56..ca36a48fa 100644
--- a/linux/drivers/media/video/cx88/cx88-core.c
+++ b/linux/drivers/media/video/cx88/cx88-core.c
@@ -1040,7 +1040,8 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
return NULL;
*vfd = *template;
vfd->minor = -1;
- vfd->parent = &pci->dev;
+ vfd->v4l2_dev = &core->v4l2_dev;
+ vfd->parent = &pci->dev;
vfd->release = video_device_release;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
core->name, type, core->board.name);
@@ -1093,6 +1094,7 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
iounmap(core->lmmio);
cx88_devcount--;
mutex_unlock(&devlist);
+ v4l2_device_unregister(&core->v4l2_dev);
kfree(core);
}
diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index 488126ad6..10cf470ce 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -242,6 +242,12 @@ static struct mt352_config dvico_fusionhdtv_dual = {
.demod_init = dvico_dual_demod_init,
};
+static struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .if2 = 45600,
+};
+
#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
@@ -1138,6 +1144,16 @@ static int dvb_register(struct cx8802_dev *dev)
if (fe0->dvb.frontend != NULL)
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
break;
+ case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &cx88_terratec_cinergy_ht_pci_mkii_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (attach_xc3028(0x61, dev) < 0)
+ goto frontend_detach;
+ }
+ break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
core->name);
diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c
index c0ff2305d..4a17a7579 100644
--- a/linux/drivers/media/video/cx88/cx88-i2c.c
+++ b/linux/drivers/media/video/cx88/cx88-i2c.c
@@ -99,7 +99,8 @@ static int cx8800_bit_getsda(void *data)
static int attach_inform(struct i2c_client *client)
{
- struct cx88_core *core = i2c_get_adapdata(client->adapter);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter);
+ struct cx88_core *core = to_core(v4l2_dev);
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->driver.name, client->addr, client->name);
@@ -108,7 +109,8 @@ static int attach_inform(struct i2c_client *client)
static int detach_inform(struct i2c_client *client)
{
- struct cx88_core *core = i2c_get_adapdata(client->adapter);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter);
+ struct cx88_core *core = to_core(v4l2_dev);
dprintk(1, "i2c detach [client=%s]\n", client->name);
return 0;
@@ -186,7 +188,7 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
core->i2c_adap.client_unregister = detach_inform;
core->i2c_algo.udelay = i2c_udelay;
core->i2c_algo.data = core;
- i2c_set_adapdata(&core->i2c_adap,core);
+ i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
core->i2c_adap.algo_data = &core->i2c_algo;
core->i2c_client.adapter = &core->i2c_adap;
strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c
index bcecb5bbd..8a2e631b7 100644
--- a/linux/drivers/media/video/cx88/cx88-input.c
+++ b/linux/drivers/media/video/cx88/cx88-input.c
@@ -49,8 +49,7 @@ struct cx88_IR {
/* poll external decoder */
int polling;
- struct work_struct work;
- struct timer_list timer;
+ struct delayed_work work;
u32 gpio_addr;
u32 last_gpio;
u32 mask_keycode;
@@ -144,13 +143,6 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
}
}
-static void ir_timer(unsigned long data)
-{
- struct cx88_IR *ir = (struct cx88_IR *)data;
-
- schedule_work(&ir->work);
-}
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
static void cx88_ir_work(void *data)
#else
@@ -160,23 +152,22 @@ static void cx88_ir_work(struct work_struct *work)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
struct cx88_IR *ir = data;
#else
- struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
+ struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work);
#endif
cx88_ir_handle_key(ir);
- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
- setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- INIT_WORK(&ir->work, cx88_ir_work, ir);
+ INIT_DELAYED_WORK(&ir->work, cx88_ir_work, ir);
#else
- INIT_WORK(&ir->work, cx88_ir_work);
+ INIT_DELAYED_WORK(&ir->work, cx88_ir_work);
#endif
- schedule_work(&ir->work);
+ schedule_delayed_work(&ir->work, 0);
}
if (ir->sampling) {
core->pci_irqmask |= PCI_INT_IR_SMPINT;
@@ -192,10 +183,8 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
}
- if (ir->polling) {
- del_timer_sync(&ir->timer);
- flush_scheduled_work();
- }
+ if (ir->polling)
+ cancel_delayed_work_sync(&ir->work);
}
/* ---------------------------------------------------------------------- */
@@ -239,6 +228,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+ case CX88_BOARD_PCHDTV_HD3000:
+ case CX88_BOARD_PCHDTV_HD5500:
ir_codes = ir_codes_hauppauge_new;
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
@@ -483,6 +474,8 @@ void cx88_ir_irq(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+ case CX88_BOARD_PCHDTV_HD3000:
+ case CX88_BOARD_PCHDTV_HD5500:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
/*
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index c8870cf06..827168d67 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -42,11 +42,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
-
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -1514,15 +1509,12 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
[ CX88_VMUX_DVB ] = "DVB",
[ CX88_VMUX_DEBUG ] = "for debug only",
};
- unsigned int n;
+ unsigned int n = i->index;
- n = i->index;
if (n >= 4)
return -EINVAL;
if (0 == INPUT(n).type)
return -EINVAL;
- memset(i,0,sizeof(*i));
- i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name,iname[INPUT(n).type]);
if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
@@ -1787,7 +1779,6 @@ static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
if (unlikely(a->index))
return -EINVAL;
- memset(a,0,sizeof(*a));
strcpy(a->name,"Radio");
return 0;
}
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index d641c24c3..d70e26000 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -25,7 +25,7 @@
#include <linux/videodev2.h>
#include <linux/kdev_t.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
@@ -232,6 +232,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_SATTRADE_ST4200 76
#define CX88_BOARD_TBS_8910 77
#define CX88_BOARD_PROF_6200 78
+#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -306,7 +307,6 @@ struct cx88_dmaqueue {
struct btcx_riscmem stopper;
u32 count;
};
-struct cx88_core;
struct cx88_core {
struct list_head devlist;
@@ -331,6 +331,7 @@ struct cx88_core {
u32 i2c_state, i2c_rc;
/* config info -- analog */
+ struct v4l2_device v4l2_dev;
unsigned int boardnr;
struct cx88_board board;
@@ -369,6 +370,11 @@ struct cx88_core {
int active_fe_id;
};
+static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
+}
+
struct cx8800_dev;
struct cx8802_dev;
diff --git a/linux/drivers/media/video/dabusb.c b/linux/drivers/media/video/dabusb.c
index b399f18c1..9e9cba431 100644
--- a/linux/drivers/media/video/dabusb.c
+++ b/linux/drivers/media/video/dabusb.c
@@ -351,7 +351,7 @@ static int dabusb_loadmem (pdabusb_t s, const char *fname)
PINTEL_HEX_RECORD ptr = firmware;
#else
const struct ihex_binrec *rec;
- const struct firmware *fw;
+ const struct firmware *uninitialized_var(fw);
#endif
dbg("Enter dabusb_loadmem (internal)");
@@ -734,7 +734,7 @@ static int dabusb_release (struct inode *inode, struct file *file)
return 0;
}
-static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{
pdabusb_t s = (pdabusb_t) file->private_data;
pbulk_transfer_t pbulk;
@@ -743,13 +743,17 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
dbg("dabusb_ioctl");
- if (s->remove_pending)
+ lock_kernel();
+ if (s->remove_pending) {
+ unlock_kernel();
return -EIO;
+ }
mutex_lock(&s->mutex);
if (!s->usbdev) {
mutex_unlock(&s->mutex);
+ unlock_kernel();
return -EIO;
}
@@ -790,6 +794,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
break;
}
mutex_unlock(&s->mutex);
+ unlock_kernel();
return ret;
}
@@ -802,7 +807,7 @@ static struct file_operations dabusb_fops =
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = dabusb_read,
- .ioctl = dabusb_ioctl,
+ .unlocked_ioctl = dabusb_ioctl,
.open = dabusb_open,
.release = dabusb_release,
};
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 74f35b6d6..6b4a204a9 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -135,6 +135,22 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
{ -1, -1, -1, -1},
};
+/* Mute/unmute */
+static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
+ {EM28XX_R08_GPIO, 5, 7, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
+ {EM28XX_R08_GPIO, 4, 7, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq compro_mute_gpio[] = {
+ {EM28XX_R08_GPIO, 6, 7, 10},
+ { -1, -1, -1, -1},
+};
+
/*
* Board definitions
*/
@@ -636,6 +652,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
+ .ir_codes = ir_codes_hauppauge_new,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -660,6 +677,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
+ .ir_codes = ir_codes_hauppauge_new,
.decoder = EM28XX_TVP5150,
#if 0 /* FIXME: add an entry at em28xx-dvb */
.has_dvb = 1,
@@ -1290,14 +1308,17 @@ struct em28xx_board em28xx_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_TVP5150,
.adecoder = EM28XX_TVAUDIO,
+ .mute_gpio = compro_mute_gpio,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = EM28XX_AMUX_LINE_IN,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = compro_unmute_tv_gpio,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = compro_unmute_svid_gpio,
} },
},
[EM2860_BOARD_KAIOMY_TVNPC_U2] = {
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index f10abc5b4..4edd3870e 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -378,6 +378,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
}
}
+ if (dev->board.mute_gpio && dev->mute)
+ em28xx_gpio_set(dev, dev->board.mute_gpio);
+ else
+ em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+
ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
if (ret < 0)
return ret;
@@ -986,7 +991,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
em28xx_irq_callback, dma_q, 1);
urb->number_of_packets = max_packets;
- urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
k = 0;
for (j = 0; j < max_packets; j++) {
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
index c76dbc029..edafe9bde 100644
--- a/linux/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -30,9 +30,6 @@
#include "lgdt330x.h"
#include "zl10353.h"
#include "s5h1409.h"
-#ifdef EM28XX_DRX397XD_SUPPORT
-#include "drx397xD.h"
-#endif
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index 1bdcf2500..e9abb2769 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -510,12 +510,17 @@ static int attach_inform(struct i2c_client *client)
dprintk1(1, "attach_inform: tvp5150 detected.\n");
break;
+ case 0xb0:
+ dprintk1(1, "attach_inform: tda9874 detected\n");
+ break;
+
default:
if (!dev->tuner_addr)
dev->tuner_addr = client->addr;
dprintk1(1, "attach inform: detected I2C address %x\n",
client->addr << 1);
+ dprintk1(1, "driver id %d\n", client->driver->id);
}
@@ -557,6 +562,7 @@ static char *i2c_devs[128] = {
[0x80 >> 1] = "msp34xx",
[0x88 >> 1] = "msp34xx",
[0xa0 >> 1] = "eeprom",
+ [0xb0 >> 1] = "tda9874",
[0xb8 >> 1] = "tvp5150a",
[0xba >> 1] = "tvp5150a",
[0xc0 >> 1] = "tuner (analog)",
diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c
index b97a1bc85..5382a6064 100644
--- a/linux/drivers/media/video/em28xx/em28xx-input.c
+++ b/linux/drivers/media/video/em28xx/em28xx-input.c
@@ -69,8 +69,7 @@ struct em28xx_IR {
/* poll external decoder */
int polling;
- struct work_struct work;
- struct timer_list timer;
+ struct delayed_work work;
unsigned int last_toggle:1;
unsigned int last_readcount;
unsigned int repeat_interval;
@@ -298,13 +297,6 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
return;
}
-static void ir_timer(unsigned long data)
-{
- struct em28xx_IR *ir = (struct em28xx_IR *)data;
-
- schedule_work(&ir->work);
-}
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void em28xx_ir_work(void *data)
#else
@@ -314,28 +306,26 @@ static void em28xx_ir_work(struct work_struct *work)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct em28xx_IR *ir = data;
#else
- struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work);
+ struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
#endif
em28xx_ir_handle_key(ir);
- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
static void em28xx_ir_start(struct em28xx_IR *ir)
{
- setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
- INIT_WORK(&ir->work, em28xx_ir_work, ir);
+ INIT_DELAYED_WORK(&ir->work, em28xx_ir_work, ir);
#else
- INIT_WORK(&ir->work, em28xx_ir_work);
+ INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
#endif
- schedule_work(&ir->work);
+ schedule_delayed_work(&ir->work, 0);
}
static void em28xx_ir_stop(struct em28xx_IR *ir)
{
- del_timer_sync(&ir->timer);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&ir->work);
}
int em28xx_ir_init(struct em28xx *dev)
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 448a02b04..ef02999ec 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -544,6 +544,13 @@ static void video_mux(struct em28xx *dev, int index)
&route);
}
+ if (dev->board.adecoder != EM28XX_NOADECODER) {
+ route.input = dev->ctl_ainput;
+ route.output = dev->ctl_aoutput;
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
+ &route);
+ }
+
em28xx_audio_analog_set(dev);
}
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 235b63499..c9be33aba 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -375,6 +375,7 @@ struct em28xx_board {
struct em28xx_reg_seq *dvb_gpio;
struct em28xx_reg_seq *suspend_gpio;
struct em28xx_reg_seq *tuner_gpio;
+ struct em28xx_reg_seq *mute_gpio;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
@@ -571,11 +572,7 @@ struct em28xx {
/* Snapshot button */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
- struct work_struct sbutton_query_work;
-#else
struct delayed_work sbutton_query_work;
-#endif
struct em28xx_dvb *dvb;
};
diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig
index a0f05ef5c..578dc4ffc 100644
--- a/linux/drivers/media/video/gspca/Kconfig
+++ b/linux/drivers/media/video/gspca/Kconfig
@@ -185,6 +185,15 @@ config USB_GSPCA_SQ905
To compile this driver as a module, choose M here: the
module will be called gspca_sq905.
+config USB_GSPCA_SQ905C
+ tristate "SQ Technologies SQ905C based USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SQ905C chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sq905c.
+
config USB_GSPCA_STK014
tristate "Syntek DV4000 (STK014) USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile
index b6ec61185..8a6643e8e 100644
--- a/linux/drivers/media/video/gspca/Makefile
+++ b/linux/drivers/media/video/gspca/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o
+obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o
obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o
@@ -43,6 +44,7 @@ gspca_spca506-objs := spca506.o
gspca_spca508-objs := spca508.o
gspca_spca561-objs := spca561.o
gspca_sq905-objs := sq905.o
+gspca_sq905c-objs := sq905c.o
gspca_stk014-objs := stk014.o
gspca_sunplus-objs := sunplus.o
gspca_t613-objs := t613.o
diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c
index de2e608bf..219cfa6fb 100644
--- a/linux/drivers/media/video/gspca/conex.c
+++ b/linux/drivers/media/video/gspca/conex.c
@@ -23,7 +23,6 @@
#include "gspca.h"
#define CONEX_CAM 1 /* special JPEG header */
-#define QUANT_VAL 0 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -37,6 +36,12 @@ struct sd {
unsigned char brightness;
unsigned char contrast;
unsigned char colors;
+ u8 quality;
+#define QUALITY_MIN 30
+#define QUALITY_MAX 60
+#define QUALITY_DEF 40
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -820,6 +825,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -836,6 +842,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
static int sd_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
cx11646_initsize(gspca_dev);
cx11646_fw(gspca_dev);
cx_sensor(gspca_dev);
@@ -846,8 +860,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
int retry = 50;
+ kfree(sd->jpeg_hdr);
+
if (!gspca_dev->present)
return;
reg_w_val(gspca_dev, 0x0000, 0x00);
@@ -873,6 +890,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
if (data[0] == 0xff && data[1] == 0xd8) {
/* start of frame */
@@ -880,7 +899,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, 0);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
data += 2;
len -= 2;
}
@@ -983,6 +1003,34 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -993,6 +1041,8 @@ static struct sd_desc sd_desc = {
.start = sd_start,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c
index dc65c363a..00e6863ed 100644
--- a/linux/drivers/media/video/gspca/finepix.c
+++ b/linux/drivers/media/video/gspca/finepix.c
@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
MODULE_LICENSE("GPL");
/* Default timeout, in ms */
-#define FPIX_TIMEOUT (HZ / 10)
+#define FPIX_TIMEOUT 250
/* Maximum transfer size to use. The windows driver reads by chunks of
* 0x2000 bytes, so do the same. Note: reading more seems to work
@@ -38,38 +38,15 @@ MODULE_LICENSE("GPL");
struct usb_fpix {
struct gspca_dev gspca_dev; /* !! must be the first item */
- /*
- * USB stuff
- */
- struct usb_ctrlrequest ctrlreq;
- struct urb *control_urb;
- struct timer_list bulk_timer;
-
- enum {
- FPIX_NOP, /* inactive, else streaming */
- FPIX_RESET, /* must reset */
- FPIX_REQ_FRAME, /* requesting a frame */
- FPIX_READ_FRAME, /* reading frame */
- } state;
-
- /*
- * Driver stuff
- */
- struct delayed_work wqe;
- struct completion can_close;
- int streaming;
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
};
/* Delay after which claim the next frame. If the delay is too small,
* the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
- * will fail every 4 or 5 frames, but 30ms is perfect. */
-#define NEXT_FRAME_DELAY (((HZ * 30) + 999) / 1000)
-
-#define dev_new_state(new_state) { \
- PDEBUG(D_STREAM, "new state from %d to %d at %s:%d", \
- dev->state, new_state, __func__, __LINE__); \
- dev->state = new_state; \
-}
+ * will fail every 4 or 5 frames, but 30ms is perfect. On the A210,
+ * 30ms is bad while 35ms is perfect. */
+#define NEXT_FRAME_DELAY 35
/* These cameras only support 320x200. */
static const struct v4l2_pix_format fpix_mode[1] = {
@@ -80,314 +57,183 @@ static const struct v4l2_pix_format fpix_mode[1] = {
.priv = 0}
};
-/* Reads part of a frame */
-static void read_frame_part(struct usb_fpix *dev)
+/* send a command to the webcam */
+static int command(struct gspca_dev *gspca_dev,
+ int order) /* 0: reset, 1: frame request */
{
- int ret;
+ static u8 order_values[2][12] = {
+ {0xc6, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0}, /* reset */
+ {0xd3, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0}, /* fr req */
+ };
- PDEBUG(D_STREAM, "read_frame_part");
-
- /* Reads part of a frame */
- ret = usb_submit_urb(dev->gspca_dev.urb[0], GFP_ATOMIC);
- if (ret) {
- dev_new_state(FPIX_RESET);
- schedule_delayed_work(&dev->wqe, 1);
- PDEBUG(D_STREAM, "usb_submit_urb failed with %d",
- ret);
- } else {
- /* Sometimes we never get a callback, so use a timer.
- * Is this masking a bug somewhere else? */
- dev->bulk_timer.expires = jiffies + msecs_to_jiffies(150);
- add_timer(&dev->bulk_timer);
- }
+ memcpy(gspca_dev->usb_buf, order_values[order], 12);
+ return usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_GET_STATUS,
+ USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+ 12, FPIX_TIMEOUT);
}
-/* Callback for URBs. */
-static void urb_callback(struct urb *urb)
+/* workqueue */
+static void dostream(struct work_struct *work)
{
- struct gspca_dev *gspca_dev = urb->context;
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
- PDEBUG(D_PACK,
- "enter urb_callback - status=%d, length=%d",
- urb->status, urb->actual_length);
-
- if (dev->state == FPIX_READ_FRAME)
- del_timer(&dev->bulk_timer);
-
- if (urb->status != 0) {
- /* We kill a stuck urb every 50 frames on average, so don't
- * display a log message for that. */
- if (urb->status != -ECONNRESET)
- PDEBUG(D_STREAM, "bad URB status %d", urb->status);
- dev_new_state(FPIX_RESET);
- schedule_delayed_work(&dev->wqe, 1);
- }
-
- switch (dev->state) {
- case FPIX_REQ_FRAME:
- dev_new_state(FPIX_READ_FRAME);
- read_frame_part(dev);
- break;
-
- case FPIX_READ_FRAME: {
- unsigned char *data = urb->transfer_buffer;
- struct gspca_frame *frame;
-
- frame = gspca_get_i_frame(&dev->gspca_dev);
- if (frame == NULL)
- gspca_dev->last_packet_type = DISCARD_PACKET;
- if (urb->actual_length < FPIX_MAX_TRANSFER ||
- (data[urb->actual_length-2] == 0xff &&
- data[urb->actual_length-1] == 0xd9)) {
-
- /* If the result is less than what was asked
- * for, then it's the end of the
- * frame. Sometime the jpeg is not complete,
- * but there's nothing we can do. We also end
- * here if the the jpeg ends right at the end
- * of the frame. */
- if (frame)
- gspca_frame_add(gspca_dev, LAST_PACKET,
- frame,
- data, urb->actual_length);
- dev_new_state(FPIX_REQ_FRAME);
- schedule_delayed_work(&dev->wqe, NEXT_FRAME_DELAY);
- } else {
+ struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct);
+ struct gspca_dev *gspca_dev = &dev->gspca_dev;
+ struct urb *urb = gspca_dev->urb[0];
+ u8 *data = urb->transfer_buffer;
+ struct gspca_frame *frame;
+ int ret = 0;
+ int len;
+
+ /* synchronize with the main driver */
+ mutex_lock(&gspca_dev->usb_lock);
+ mutex_unlock(&gspca_dev->usb_lock);
+ PDEBUG(D_STREAM, "dostream started");
+
+ /* loop reading a frame */
+again:
+ while (gspca_dev->present && gspca_dev->streaming) {
+
+ /* request a frame */
+ mutex_lock(&gspca_dev->usb_lock);
+ ret = command(gspca_dev, 1);
+ mutex_unlock(&gspca_dev->usb_lock);
+ if (ret < 0)
+ break;
+ if (!gspca_dev->present || !gspca_dev->streaming)
+ break;
+
+ /* the frame comes in parts */
+ for (;;) {
+ ret = usb_bulk_msg(gspca_dev->dev,
+ urb->pipe,
+ data,
+ FPIX_MAX_TRANSFER,
+ &len, FPIX_TIMEOUT);
+ if (ret < 0) {
+ /* Most of the time we get a timeout
+ * error. Just restart. */
+ goto again;
+ }
+ if (!gspca_dev->present || !gspca_dev->streaming)
+ goto out;
+ frame = gspca_get_i_frame(&dev->gspca_dev);
+ if (frame == NULL)
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+
+ if (len < FPIX_MAX_TRANSFER ||
+ (data[len - 2] == 0xff &&
+ data[len - 1] == 0xd9)) {
+
+ /* If the result is less than what was asked
+ * for, then it's the end of the
+ * frame. Sometimes the jpeg is not complete,
+ * but there's nothing we can do. We also end
+ * here if the the jpeg ends right at the end
+ * of the frame. */
+ if (frame)
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ data, len);
+ break;
+ }
/* got a partial image */
if (frame)
gspca_frame_add(gspca_dev,
gspca_dev->last_packet_type
- == LAST_PACKET
+ == LAST_PACKET
? FIRST_PACKET : INTER_PACKET,
- frame,
- data, urb->actual_length);
- read_frame_part(dev);
+ frame, data, len);
}
- break;
- }
-
- case FPIX_NOP:
- case FPIX_RESET:
- PDEBUG(D_STREAM, "invalid state %d", dev->state);
- break;
- }
-}
-
-/* Request a new frame */
-static void request_frame(struct usb_fpix *dev)
-{
- int ret;
- struct gspca_dev *gspca_dev = &dev->gspca_dev;
- /* Setup command packet */
- memset(gspca_dev->usb_buf, 0, 12);
- gspca_dev->usb_buf[0] = 0xd3;
- gspca_dev->usb_buf[7] = 0x01;
-
- /* Request a frame */
- dev->ctrlreq.bRequestType =
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- dev->ctrlreq.bRequest = USB_REQ_GET_STATUS;
- dev->ctrlreq.wValue = 0;
- dev->ctrlreq.wIndex = 0;
- dev->ctrlreq.wLength = cpu_to_le16(12);
-
- usb_fill_control_urb(dev->control_urb,
- gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- (unsigned char *) &dev->ctrlreq,
- gspca_dev->usb_buf,
- 12, urb_callback, gspca_dev);
-
- ret = usb_submit_urb(dev->control_urb, GFP_ATOMIC);
- if (ret) {
- dev_new_state(FPIX_RESET);
- schedule_delayed_work(&dev->wqe, 1);
- PDEBUG(D_STREAM, "usb_submit_urb failed with %d", ret);
+ /* We must wait before trying reading the next
+ * frame. If we don't, or if the delay is too short,
+ * the camera will disconnect. */
+ msleep(NEXT_FRAME_DELAY);
}
-}
-
-/*--------------------------------------------------------------------------*/
-/* State machine. */
-static void fpix_sm(struct work_struct *work)
-{
- struct usb_fpix *dev = container_of(work, struct usb_fpix, wqe.work);
-
- PDEBUG(D_STREAM, "fpix_sm state %d", dev->state);
-
- /* verify that the device wasn't unplugged */
- if (!dev->gspca_dev.present) {
- PDEBUG(D_STREAM, "device is gone");
- dev_new_state(FPIX_NOP);
- complete(&dev->can_close);
- return;
- }
-
- if (!dev->streaming) {
- PDEBUG(D_STREAM, "stopping state machine");
- dev_new_state(FPIX_NOP);
- complete(&dev->can_close);
- return;
- }
-
- switch (dev->state) {
- case FPIX_RESET:
- dev_new_state(FPIX_REQ_FRAME);
- schedule_delayed_work(&dev->wqe, HZ / 10);
- break;
-
- case FPIX_REQ_FRAME:
- /* get an image */
- request_frame(dev);
- break;
-
- case FPIX_NOP:
- case FPIX_READ_FRAME:
- PDEBUG(D_STREAM, "invalid state %d", dev->state);
- break;
- }
+out:
+ PDEBUG(D_STREAM, "dostream stopped");
}
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
+ struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
cam->cam_mode = fpix_mode;
cam->nmodes = 1;
cam->bulk_size = FPIX_MAX_TRANSFER;
-/* gspca_dev->nbalt = 1; * use bulk transfer */
- return 0;
-}
-
-/* Stop streaming and free the ressources allocated by sd_start. */
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+ INIT_WORK(&dev->work_struct, dostream);
- dev->streaming = 0;
-
- /* Stop the state machine */
- if (dev->state != FPIX_NOP)
- wait_for_completion(&dev->can_close);
-}
-
-/* called on streamoff with alt 0 and disconnect */
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
- usb_free_urb(dev->control_urb);
- dev->control_urb = NULL;
-}
-
-/* Kill an URB that hasn't completed. */
-static void timeout_kill(unsigned long data)
-{
- struct urb *urb = (struct urb *) data;
-
- usb_unlink_urb(urb);
+ return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
- INIT_DELAYED_WORK(&dev->wqe, fpix_sm);
-
- init_timer(&dev->bulk_timer);
- dev->bulk_timer.function = timeout_kill;
-
return 0;
}
+/* start the camera */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
- int ret;
- int size_ret;
+ int ret, len;
/* Init the device */
- memset(gspca_dev->usb_buf, 0, 12);
- gspca_dev->usb_buf[0] = 0xc6;
- gspca_dev->usb_buf[8] = 0x20;
-
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- USB_REQ_GET_STATUS,
- USB_DIR_OUT | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
- 12, FPIX_TIMEOUT);
-
- if (ret != 12) {
- PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
- ret = -EIO;
- goto error;
+ ret = command(gspca_dev, 0);
+ if (ret < 0) {
+ PDEBUG(D_STREAM, "init failed %d", ret);
+ return ret;
}
/* Read the result of the command. Ignore the result, for it
* varies with the device. */
ret = usb_bulk_msg(gspca_dev->dev,
gspca_dev->urb[0]->pipe,
- gspca_dev->usb_buf, FPIX_MAX_TRANSFER, &size_ret,
+ gspca_dev->urb[0]->transfer_buffer,
+ FPIX_MAX_TRANSFER, &len,
FPIX_TIMEOUT);
- if (ret != 0) {
- PDEBUG(D_STREAM, "usb_bulk_msg failed (%d)", ret);
- ret = -EIO;
- goto error;
+ if (ret < 0) {
+ PDEBUG(D_STREAM, "usb_bulk_msg failed %d", ret);
+ return ret;
}
/* Request a frame, but don't read it */
- memset(gspca_dev->usb_buf, 0, 12);
- gspca_dev->usb_buf[0] = 0xd3;
- gspca_dev->usb_buf[7] = 0x01;
-
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- USB_REQ_GET_STATUS,
- USB_DIR_OUT | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
- 12, FPIX_TIMEOUT);
- if (ret != 12) {
- PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
- ret = -EIO;
- goto error;
+ ret = command(gspca_dev, 1);
+ if (ret < 0) {
+ PDEBUG(D_STREAM, "frame request failed %d", ret);
+ return ret;
}
/* Again, reset bulk in endpoint */
usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
- /* Allocate a control URB */
- dev->control_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->control_urb) {
- PDEBUG(D_STREAM, "No free urbs available");
- ret = -EIO;
- goto error;
- }
-
- /* Various initializations. */
- init_completion(&dev->can_close);
- dev->bulk_timer.data = (unsigned long)dev->gspca_dev.urb[0];
- dev->gspca_dev.urb[0]->complete = urb_callback;
- dev->streaming = 1;
-
- /* Schedule a frame request. */
- dev_new_state(FPIX_REQ_FRAME);
- schedule_delayed_work(&dev->wqe, 1);
+ /* 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;
+}
+
+/* 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 usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-error:
- /* Free the ressources */
- sd_stopN(gspca_dev);
- sd_stop0(gspca_dev);
- return ret;
+ /* wait for the work queue to terminate */
+ mutex_unlock(&gspca_dev->usb_lock);
+ destroy_workqueue(dev->work_thread);
+ mutex_lock(&gspca_dev->usb_lock);
+ dev->work_thread = NULL;
}
/* Table of supported USB devices */
@@ -422,12 +268,11 @@ MODULE_DEVICE_TABLE(usb, device_table);
/* sub-driver description */
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = MODULE_NAME,
.config = sd_config,
- .init = sd_init,
- .start = sd_start,
- .stopN = sd_stopN,
- .stop0 = sd_stop0,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
};
/* -- device connect -- */
@@ -441,13 +286,13 @@ static int sd_probe(struct usb_interface *intf,
}
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
- .id_table = device_table,
- .probe = sd_probe,
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
.disconnect = gspca_disconnect,
#ifdef CONFIG_PM
.suspend = gspca_suspend,
- .resume = gspca_resume,
+ .resume = gspca_resume,
#endif
};
@@ -455,12 +300,14 @@ static struct usb_driver sd_driver = {
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);
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index 8d78b9287..93c35d083 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -486,14 +486,14 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
i = gspca_dev->alt; /* previous alt setting */
/* try isoc */
- while (--i > 0) { /* alt 0 is unusable */
+ while (--i >= 0) {
ep = alt_xfer(&intf->altsetting[i],
USB_ENDPOINT_XFER_ISOC);
if (ep)
break;
}
- /* if no isoc, try bulk */
+ /* if no isoc, try bulk (alt 0 only) */
if (ep == NULL) {
ep = alt_xfer(&intf->altsetting[0],
USB_ENDPOINT_XFER_BULK);
@@ -501,6 +501,8 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
err("no transfer endpoint found");
return NULL;
}
+ i = 0;
+ gspca_dev->bulk = 1;
}
PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
i, ep->desc.bEndpointAddress);
@@ -527,7 +529,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
/* calculate the packet size and the number of packets */
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- if (gspca_dev->alt != 0) { /* isoc */
+ if (!gspca_dev->bulk) { /* isoc */
/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
@@ -627,7 +629,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
goto out;
/* clear the bulk endpoint */
- if (gspca_dev->alt == 0) /* if bulk transfer */
+ if (gspca_dev->bulk)
usb_clear_halt(gspca_dev->dev,
gspca_dev->urb[0]->pipe);
@@ -640,7 +642,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
gspca_dev->streaming = 1;
/* some bulk transfers are started by the subdriver */
- if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0)
+ if (gspca_dev->bulk && gspca_dev->cam.bulk_nurbs == 0)
break;
/* submit the URBs */
@@ -775,7 +777,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
fmtdesc->pixelformat = fmt_tb[index];
if (gspca_is_compressed(fmt_tb[index]))
fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
- fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
@@ -972,8 +973,6 @@ static int vidioc_querycap(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int ret;
- memset(cap, 0, sizeof *cap);
-
/* protect the access to the usb device */
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
@@ -1111,7 +1110,6 @@ static int vidioc_s_audio(struct file *file, void *priv,
static int vidioc_g_audio(struct file *file, void *priv,
struct v4l2_audio *audio)
{
- memset(audio, 0, sizeof *audio);
strcpy(audio->name, "Microphone");
return 0;
}
@@ -1145,7 +1143,6 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (input->index != 0)
return -EINVAL;
- memset(input, 0, sizeof *input);
input->type = V4L2_INPUT_TYPE_CAMERA;
strncpy(input->name, gspca_dev->sd_desc->name,
sizeof input->name);
@@ -1353,8 +1350,6 @@ static int vidioc_g_parm(struct file *filp, void *priv,
{
struct gspca_dev *gspca_dev = priv;
- memset(parm, 0, sizeof *parm);
- parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm->parm.capture.readbuffers = gspca_dev->nbufread;
if (gspca_dev->sd_desc->get_streamparm) {
@@ -1423,7 +1418,6 @@ static int vidiocgmbuf(struct file *file, void *priv,
{
struct v4l2_format fmt;
- memset(&fmt, 0, sizeof fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
i = gspca_dev->cam.nmodes - 1; /* highest mode */
fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h
index 6f172e9e5..e4d4cf6ce 100644
--- a/linux/drivers/media/video/gspca/gspca.h
+++ b/linux/drivers/media/video/gspca/gspca.h
@@ -167,6 +167,7 @@ struct gspca_dev {
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
__u8 nbalt; /* number of USB alternate settings */
+ u8 bulk; /* image transfer by 0:isoc / 1:bulk */
};
int gspca_dev_probe(struct usb_interface *intf,
diff --git a/linux/drivers/media/video/gspca/jpeg.h b/linux/drivers/media/video/gspca/jpeg.h
index 7d2df9720..de63c3680 100644
--- a/linux/drivers/media/video/gspca/jpeg.h
+++ b/linux/drivers/media/video/gspca/jpeg.h
@@ -27,42 +27,16 @@
/*
* generation options
* CONEX_CAM Conexant if present
- * QUANT_VAL quantization table (0..8)
*/
-/*
- * JPEG header:
- * - start of jpeg frame
- * - quantization table
- * - huffman table
- * - start of SOF0
- */
+/* JPEG header */
static const u8 jpeg_head[] = {
0xff, 0xd8, /* jpeg */
+
+/* quantization table quality 50% */
0xff, 0xdb, 0x00, 0x84, /* DQT */
-#if QUANT_VAL == 0
-/* index 0 - Q40*/
-0, /* quantization table part 1 */
- 0x14, 0x0e, 0x0f, 0x12, 0x0f, 0x0d, 0x14, 0x12,
- 0x10, 0x12, 0x17, 0x15, 0x14, 0x18, 0x1e, 0x32,
- 0x21, 0x1e, 0x1c, 0x1c, 0x1e, 0x3d, 0x2c, 0x2e,
- 0x24, 0x32, 0x49, 0x40, 0x4c, 0x4b, 0x47, 0x40,
- 0x46, 0x45, 0x50, 0x5a, 0x73, 0x62, 0x50, 0x55,
- 0x6d, 0x56, 0x45, 0x46, 0x64, 0x88, 0x65, 0x6d,
- 0x77, 0x7b, 0x81, 0x82, 0x81, 0x4e, 0x60, 0x8d,
- 0x97, 0x8c, 0x7d, 0x96, 0x73, 0x7e, 0x81, 0x7c,
-1, /* quantization table part 2 */
- 0x15, 0x17, 0x17, 0x1e, 0x1a, 0x1e, 0x3b, 0x21,
- 0x21, 0x3b, 0x7c, 0x53, 0x46, 0x53, 0x7c, 0x0c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
-#elif QUANT_VAL == 1
-/* index 1 - Q50 */
0,
+#define JPEG_QT0_OFFSET 7
0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
@@ -72,6 +46,7 @@ static const u8 jpeg_head[] = {
0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
1,
+#define JPEG_QT1_OFFSET 72
0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
@@ -80,149 +55,6 @@ static const u8 jpeg_head[] = {
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-#elif QUANT_VAL == 2
-/* index 2 Q60 */
-0,
- 0x0d, 0x09, 0x0a, 0x0b, 0x0a, 0x08, 0x0d, 0x0b,
- 0x0a, 0x0b, 0x0e, 0x0e, 0x0d, 0x0f, 0x13, 0x20,
- 0x15, 0x13, 0x12, 0x12, 0x13, 0x27, 0x1c, 0x1e,
- 0x17, 0x20, 0x2e, 0x29, 0x31, 0x30, 0x2e, 0x29,
- 0x2d, 0x2c, 0x33, 0x3a, 0x4a, 0x3e, 0x33, 0x36,
- 0x46, 0x37, 0x2c, 0x2d, 0x40, 0x57, 0x41, 0x46,
- 0x4c, 0x4e, 0x52, 0x53, 0x52, 0x32, 0x3e, 0x5a,
- 0x61, 0x5a, 0x50, 0x60, 0x4a, 0x51, 0x52, 0x4f,
-1,
- 0x0e, 0x0e, 0x0e, 0x13, 0x11, 0x13, 0x26, 0x15,
- 0x15, 0x26, 0x4f, 0x35, 0x2d, 0x35, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
-#elif QUANT_VAL == 3
-/* index 3 - Q70 */
-0,
- 0x0a, 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08,
- 0x08, 0x08, 0x0b, 0x0a, 0x0a, 0x0b, 0x0e, 0x18,
- 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15, 0x16,
- 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f,
- 0x22, 0x21, 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29,
- 0x34, 0x29, 0x21, 0x22, 0x30, 0x41, 0x31, 0x34,
- 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
- 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b,
-1,
- 0x0a, 0x0b, 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10,
- 0x10, 0x1c, 0x3b, 0x28, 0x22, 0x28, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
-#elif QUANT_VAL == 4
-/* index 4 - Q80 */
-0,
- 0x06, 0x04, 0x05, 0x06, 0x05, 0x04, 0x06, 0x06,
- 0x05, 0x06, 0x07, 0x07, 0x06, 0x08, 0x0a, 0x10,
- 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, 0x0f,
- 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14,
- 0x16, 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b,
- 0x23, 0x1c, 0x16, 0x16, 0x20, 0x2c, 0x20, 0x23,
- 0x26, 0x27, 0x29, 0x2a, 0x29, 0x19, 0x1f, 0x2d,
- 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29, 0x28,
-1,
- 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
- 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
-#elif QUANT_VAL == 5
-/* index 5 - Q85 */
-0,
- 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04,
- 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c,
- 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b,
- 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f,
- 0x11, 0x11, 0x13, 0x16, 0x1c, 0x17, 0x13, 0x14,
- 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1a,
- 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22,
- 0x24, 0x22, 0x1e, 0x24, 0x1c, 0x1e, 0x1f, 0x1e,
-1,
- 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0e, 0x08,
- 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
-#elif QUANT_VAL == 6
-/* index 6 - 86 */
-0,
- 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
- 0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B,
- 0x07, 0x07, 0x06, 0x06, 0x07, 0x0e, 0x0a, 0x0a,
- 0x08, 0x0B, 0x10, 0x0e, 0x11, 0x11, 0x10, 0x0e,
- 0x10, 0x0f, 0x12, 0x14, 0x1a, 0x16, 0x12, 0x13,
- 0x18, 0x13, 0x0f, 0x10, 0x16, 0x1f, 0x17, 0x18,
- 0x1b, 0x1b, 0x1d, 0x1d, 0x1d, 0x11, 0x16, 0x20,
- 0x22, 0x1f, 0x1c, 0x22, 0x1a, 0x1c, 0x1d, 0x1c,
-1,
- 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07,
- 0x07, 0x0D, 0x1c, 0x12, 0x10, 0x12, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
-#elif QUANT_VAL == 7
-/* index 7 - 88 */
-0,
- 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03,
- 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0a,
- 0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09,
- 0x07, 0x0a, 0x0e, 0x0c, 0x0f, 0x0e, 0x0e, 0x0c,
- 0x0d, 0x0d, 0x0f, 0x11, 0x16, 0x13, 0x0f, 0x10,
- 0x15, 0x11, 0x0d, 0x0d, 0x13, 0x1a, 0x13, 0x15,
- 0x17, 0x18, 0x19, 0x19, 0x19, 0x0f, 0x12, 0x1b,
- 0x1d, 0x1b, 0x18, 0x1d, 0x16, 0x18, 0x19, 0x18,
-1,
- 0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06,
- 0x06, 0x0B, 0x18, 0x10, 0x0d, 0x10, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-#elif QUANT_VAL == 8
-/* index 8 - ?? */
-0,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05,
- 0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06,
- 0x07, 0x07, 0x08, 0x09, 0x0c, 0x0a, 0x08, 0x09,
- 0x0B, 0x09, 0x07, 0x07, 0x0a, 0x0e, 0x0a, 0x0b,
- 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x08, 0x0a, 0x0e,
- 0x0f, 0x0e, 0x0d, 0x0f, 0x0c, 0x0d, 0x0d, 0x0c,
-1,
- 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03,
- 0x03, 0x06, 0x0c, 0x08, 0x07, 0x08, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-#else
-#error "Invalid quantization table"
-#endif
/* huffman table */
0xff, 0xc4, 0x01, 0xa2,
@@ -280,55 +112,57 @@ static const u8 jpeg_head[] = {
0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
#ifdef CONEX_CAM
/* the Conexant frames start with SOF0 */
+#define JPEG_HDR_SZ 556
#else
0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */
0x08, /* data precision */
-#endif
-};
-
-#ifndef CONEX_CAM
-/* variable part:
- * 0x01, 0xe0, height
- * 0x02, 0x80, width
- * 0x03, component number
- * 0x01,
- * 0x21, samples Y
- */
-
-/* end of header */
-static u8 eoh[] = {
+#define JPEG_HEIGHT_OFFSET 561
+ 0x01, 0xe0, /* height */
+ 0x02, 0x80, /* width */
+ 0x03, /* component number */
+ 0x01,
+ 0x21, /* samples Y */
0x00, /* quant Y */
0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */
0x03, 0x11, 0x01,
0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */
0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
-};
+#define JPEG_HDR_SZ 589
#endif
+};
-/* -- output the JPEG header -- */
-static void jpeg_put_header(struct gspca_dev *gspca_dev,
- struct gspca_frame *frame,
- int samplesY)
+/* define the JPEG header */
+static void jpeg_define(u8 *jpeg_hdr,
+ int height,
+ int width,
+ int samplesY)
{
+ memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
#ifndef CONEX_CAM
- u8 tmpbuf[8];
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY;
#endif
+}
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
- jpeg_head, sizeof jpeg_head);
-#ifndef CONEX_CAM
- tmpbuf[0] = gspca_dev->height >> 8;
- tmpbuf[1] = gspca_dev->height & 0xff;
- tmpbuf[2] = gspca_dev->width >> 8;
- tmpbuf[3] = gspca_dev->width & 0xff;
- tmpbuf[4] = 0x03; /* component number */
- tmpbuf[5] = 0x01; /* first component */
- tmpbuf[6] = samplesY;
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- tmpbuf, 7);
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- eoh, sizeof eoh);
-#endif
+/* set the JPEG quality */
+static void jpeg_set_qual(u8 *jpeg_hdr,
+ int quality)
+{
+ int i, sc;
+
+ if (quality < 50)
+ sc = 5000 / quality;
+ else
+ sc = 200 - quality * 2;
+ for (i = 0; i < 64; i++) {
+ jpeg_hdr[JPEG_QT0_OFFSET + i] =
+ (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+ jpeg_hdr[JPEG_QT1_OFFSET + i] =
+ (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+ }
}
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 2bd7d4d99..7e79f7eca 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -104,7 +104,11 @@ int s5k4aa_probe(struct sd *sd)
}
/* Test some registers, but we don't know their exact meaning yet */
- if (m5602_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
+ if (m5602_read_sensor(sd, 0x00, prod_id, 2))
+ return -ENODEV;
+ if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
+ return -ENODEV;
+ if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
return -ENODEV;
if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c
index c5a19b5bc..789fd178a 100644
--- a/linux/drivers/media/video/gspca/mars.c
+++ b/linux/drivers/media/video/gspca/mars.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "mars"
#include "gspca.h"
-#define QUANT_VAL 1 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -37,6 +36,12 @@ struct sd {
u8 colors;
u8 gamma;
u8 sharpness;
+ u8 quality;
+#define QUALITY_MIN 40
+#define QUALITY_MAX 70
+#define QUALITY_DEF 50
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -69,10 +74,10 @@ static struct ctrl sd_ctrls[] = {
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Color",
- .minimum = 0,
- .maximum = 220,
+ .minimum = 1,
+ .maximum = 255,
.step = 1,
-#define COLOR_DEF 190
+#define COLOR_DEF 200
.default_value = COLOR_DEF,
},
.set = sd_setcolors,
@@ -176,6 +181,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->colors = COLOR_DEF;
sd->gamma = GAMMA_DEF;
sd->sharpness = SHARPNESS_DEF;
+ sd->quality = QUALITY_DEF;
gspca_dev->nbalt = 9; /* use the altsetting 08 */
return 0;
}
@@ -191,7 +197,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int err_code;
u8 *data;
- int i, val;
+ int i;
+
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
data = gspca_dev->usb_buf;
@@ -253,9 +265,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[1] = 0; /* reg 94, Y Gain (auto) */
#if 1
/*jfm: from win trace*/
- val = sd->colors * 0x40 + 0x400;
- data[2] = val; /* reg 0x5f/0x60 (LE) = saturation */
- data[3] = val >> 8;
+ /* reg 0x5f/0x60 (LE) = saturation */
+ /* h (60): xxxx x100
+ * l (5f): xxxx x000 */
+ data[2] = sd->colors << 3;
+ data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
data[4] = sd->brightness; /* reg 0x61 = brightness */
data[5] = 0x00;
#else
@@ -339,11 +353,19 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_ERR, "Camera Stop failed");
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
int p;
if (len < 6) {
@@ -366,7 +388,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
frame, data, p);
/* put the JPEG header */
- jpeg_put_header(gspca_dev, frame, 0x21);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
data += p + 16;
len -= p + 16;
break;
@@ -403,10 +426,11 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
sd->colors = val;
if (gspca_dev->streaming) {
- val = val * 0x40 + 0x400;
+
+ /* see sd_start */
gspca_dev->usb_buf[0] = 0x5f;
- gspca_dev->usb_buf[1] = val;
- gspca_dev->usb_buf[2] = val >> 8;
+ gspca_dev->usb_buf[1] = sd->colors << 3;
+ gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
reg_w(gspca_dev, 3);
}
return 0;
@@ -462,6 +486,34 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -471,7 +523,10 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c
index 5ec5ce6e3..2a901a4a6 100644
--- a/linux/drivers/media/video/gspca/mr97310a.c
+++ b/linux/drivers/media/video/gspca/mr97310a.c
@@ -29,9 +29,7 @@ MODULE_LICENSE("GPL");
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
-
u8 sof_read;
- u8 header_read;
};
/* V4L2 controls supported by the driver */
@@ -285,7 +283,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
- struct sd *sd = (struct sd *) gspca_dev;
unsigned char *sof;
sof = pac_find_sof(gspca_dev, data, len);
@@ -300,25 +297,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
n = 0;
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, n);
- sd->header_read = 0;
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+ /* Start next frame. */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ pac_sof_marker, sizeof pac_sof_marker);
len -= sof - data;
data = sof;
}
- if (sd->header_read < 7) {
- int needed;
-
- /* skip the rest of the header */
- needed = 7 - sd->header_read;
- if (len <= needed) {
- sd->header_read += len;
- return;
- }
- data += needed;
- len -= needed;
- sd->header_read = 7;
- }
-
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
diff --git a/linux/drivers/media/video/gspca/ov534.c b/linux/drivers/media/video/gspca/ov534.c
index de0ab8e06..0f5ec9317 100644
--- a/linux/drivers/media/video/gspca/ov534.c
+++ b/linux/drivers/media/video/gspca/ov534.c
@@ -1,7 +1,8 @@
/*
- * ov534/ov772x gspca driver
+ * ov534 gspca driver
* Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
* Copyright (C) 2008 Jim Paris <jim@jtan.com>
+ * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr
*
* Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
* USB protocol reverse engineered by Jim Paris <jim@jtan.com>
@@ -26,7 +27,7 @@
#include "gspca.h"
-#define OV534_REG_ADDRESS 0xf1 /* ? */
+#define OV534_REG_ADDRESS 0xf1 /* sensor address */
#define OV534_REG_SUBADDR 0xf2
#define OV534_REG_WRITE 0xf3
#define OV534_REG_READ 0xf4
@@ -46,9 +47,13 @@ MODULE_LICENSE("GPL");
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u32 last_fid;
__u32 last_pts;
- int frame_rate;
+ u16 last_fid;
+ u8 frame_rate;
+
+ u8 sensor;
+#define SENSOR_OV772X 0
+#define SENSOR_OV965X 1
};
/* V4L2 controls supported by the driver */
@@ -63,114 +68,7 @@ static const struct v4l2_pix_format vga_mode[] = {
.priv = 0},
};
-static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
-{
- struct usb_device *udev = gspca_dev->dev;
- int ret;
-
- PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
- gspca_dev->usb_buf[0] = val;
- ret = usb_control_msg(udev,
- usb_sndctrlpipe(udev, 0),
- 0x1,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
- if (ret < 0)
- PDEBUG(D_ERR, "write failed");
-}
-
-static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
-{
- struct usb_device *udev = gspca_dev->dev;
- int ret;
-
- ret = usb_control_msg(udev,
- usb_rcvctrlpipe(udev, 0),
- 0x1,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
- PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
- if (ret < 0)
- PDEBUG(D_ERR, "read failed");
- return gspca_dev->usb_buf[0];
-}
-
-/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
- * (direction and output)? */
-static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
-{
- u8 data;
-
- PDEBUG(D_CONF, "led status: %d", status);
-
- data = ov534_reg_read(gspca_dev, 0x21);
- data |= 0x80;
- ov534_reg_write(gspca_dev, 0x21, data);
-
- data = ov534_reg_read(gspca_dev, 0x23);
- if (status)
- data |= 0x80;
- else
- data &= ~(0x80);
-
- ov534_reg_write(gspca_dev, 0x23, data);
-}
-
-static int sccb_check_status(struct gspca_dev *gspca_dev)
-{
- u8 data;
- int i;
-
- for (i = 0; i < 5; i++) {
- data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
-
- switch (data) {
- case 0x00:
- return 1;
- case 0x04:
- return 0;
- case 0x03:
- break;
- default:
- PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
- data, i + 1);
- }
- }
- return 0;
-}
-
-static void sccb_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
-{
- PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%02x", reg, val);
- ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
- ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
- ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
-
- if (!sccb_check_status(gspca_dev))
- PDEBUG(D_ERR, "sccb_reg_write failed");
-}
-
-#ifdef GSPCA_DEBUG
-static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
-{
- ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
- ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
- if (!sccb_check_status(gspca_dev))
- PDEBUG(D_ERR, "sccb_reg_read failed 1");
-
- ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
- if (!sccb_check_status(gspca_dev))
- PDEBUG(D_ERR, "sccb_reg_read failed 2");
-
- return ov534_reg_read(gspca_dev, OV534_REG_READ);
-}
-#endif
-
-static const __u8 ov534_reg_initdata[][2] = {
- { 0xe7, 0x3a },
-
- { OV534_REG_ADDRESS, 0x42 }, /* select OV772x sensor */
-
+static const u8 bridge_init_ov722x[][2] = {
{ 0xc2, 0x0c },
{ 0x88, 0xf8 },
{ 0xc3, 0x69 },
@@ -228,7 +126,7 @@ static const __u8 ov534_reg_initdata[][2] = {
{ 0xc2, 0x0c },
};
-static const __u8 ov772x_reg_initdata[][2] = {
+static const u8 sensor_init_ov722x[][2] = {
{ 0x12, 0x80 },
{ 0x11, 0x01 },
@@ -311,6 +209,475 @@ static const __u8 ov772x_reg_initdata[][2] = {
{ 0x0c, 0xd0 }
};
+static const u8 bridge_init_ov965x[][2] = {
+ {0x88, 0xf8},
+ {0x89, 0xff},
+ {0x76, 0x03},
+ {0x92, 0x03},
+ {0x95, 0x10},
+ {0xe2, 0x00},
+ {0xe7, 0x3e},
+ {0x8d, 0x1c},
+ {0x8e, 0x00},
+ {0x8f, 0x00},
+ {0x1f, 0x00},
+ {0xc3, 0xf9},
+ {0x89, 0xff},
+ {0x88, 0xf8},
+ {0x76, 0x03},
+ {0x92, 0x01},
+ {0x93, 0x18},
+ {0x1c, 0x0a},
+ {0x1d, 0x48},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x34, 0x05},
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0x34, 0x05},
+ {0xe7, 0x2e},
+ {0x31, 0xf9},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x25, 0x42},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_init_ov965x[][2] = {
+ {0x12, 0x80}, /* com7 - reset */
+ {0x00, 0x00}, /* gain */
+ {0x01, 0x80}, /* blue */
+ {0x02, 0x80}, /* red */
+ {0x03, 0x1b}, /* vref */
+ {0x04, 0x03}, /* com1 - exposure low bits */
+ {0x0b, 0x57}, /* ver */
+ {0x0e, 0x61}, /* com5 */
+ {0x0f, 0x42}, /* com6 */
+ {0x11, 0x00}, /* clkrc */
+ {0x12, 0x02}, /* com7 */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x14, 0x28}, /* com9 */
+ {0x16, 0x24}, /* rsvd16 */
+ {0x17, 0x1d}, /* hstart*/
+ {0x18, 0xbd}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x81}, /* vstop*/
+ {0x1e, 0x04}, /* mvfp */
+ {0x24, 0x3c}, /* aew */
+ {0x25, 0x36}, /* aeb */
+ {0x26, 0x71}, /* vpt */
+ {0x27, 0x08}, /* bbias */
+ {0x28, 0x08}, /* gbbias */
+ {0x29, 0x15}, /* gr com */
+ {0x2a, 0x00},
+ {0x2b, 0x00},
+ {0x2c, 0x08}, /* rbias */
+ {0x32, 0xff}, /* href */
+ {0x33, 0x00}, /* chlf */
+ {0x34, 0x3f}, /* arblm */
+ {0x35, 0x00}, /* rsvd35 */
+ {0x36, 0xf8}, /* rsvd36 */
+ {0x38, 0x72}, /* acom38 */
+ {0x39, 0x57}, /* ofon */
+ {0x3a, 0x80}, /* tslb */
+ {0x3b, 0xc4},
+ {0x3d, 0x99}, /* com13 */
+ {0x3f, 0xc1},
+ {0x40, 0xc0}, /* com15 */
+ {0x41, 0x40}, /* com16 */
+ {0x42, 0xc0},
+ {0x43, 0x0a},
+ {0x44, 0xf0},
+ {0x45, 0x46},
+ {0x46, 0x62},
+ {0x47, 0x2a},
+ {0x48, 0x3c},
+ {0x4a, 0xfc},
+ {0x4b, 0xfc},
+ {0x4c, 0x7f},
+ {0x4d, 0x7f},
+ {0x4e, 0x7f},
+ {0x4f, 0x98},
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a},
+ {0x59, 0x85},
+ {0x5a, 0xa9},
+ {0x5b, 0x64},
+ {0x5c, 0x84},
+ {0x5d, 0x53},
+ {0x5e, 0x0e},
+ {0x5f, 0xf0},
+ {0x60, 0xf0},
+ {0x61, 0xf0},
+ {0x62, 0x00}, /* lcc1 */
+ {0x63, 0x00}, /* lcc2 */
+ {0x64, 0x02}, /* lcc3 */
+ {0x65, 0x16}, /* lcc4 */
+ {0x66, 0x01}, /* lcc5 */
+ {0x69, 0x02}, /* hv */
+ {0x6b, 0x5a}, /* dbvl */
+ {0x6c, 0x04},
+ {0x6d, 0x55},
+ {0x6e, 0x00},
+ {0x6f, 0x9d},
+ {0x70, 0x21},
+ {0x71, 0x78},
+ {0x72, 0x00},
+ {0x73, 0x01},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0x77, 0x02},
+ {0x7a, 0x12},
+ {0x7b, 0x08},
+ {0x7c, 0x16},
+ {0x7d, 0x30},
+ {0x7e, 0x5e},
+ {0x7f, 0x72},
+ {0x80, 0x82},
+ {0x81, 0x8e},
+ {0x82, 0x9a},
+ {0x83, 0xa4},
+ {0x84, 0xac},
+ {0x85, 0xb8},
+ {0x86, 0xc3},
+ {0x87, 0xd6},
+ {0x88, 0xe6},
+ {0x89, 0xf2},
+ {0x8a, 0x03},
+ {0x8c, 0x89},
+ {0x14, 0x28}, /* com9 */
+ {0x90, 0x7d},
+ {0x91, 0x7b},
+ {0x9d, 0x03},
+ {0x9e, 0x04},
+ {0x9f, 0x7a},
+ {0xa0, 0x79},
+ {0xa1, 0x40}, /* aechm */
+ {0xa4, 0x50},
+ {0xa5, 0x68}, /* com26 */
+ {0xa6, 0x4a},
+ {0xa8, 0xc1}, /* acoma8 */
+ {0xa9, 0xef}, /* acoma9 */
+ {0xaa, 0x92},
+ {0xab, 0x04},
+ {0xac, 0x80},
+ {0xad, 0x80},
+ {0xae, 0x80},
+ {0xaf, 0x80},
+ {0xb2, 0xf2},
+ {0xb3, 0x20},
+ {0xb4, 0x20},
+ {0xb5, 0x00},
+ {0xb6, 0xaf},
+ {0xbb, 0xae},
+ {0xbc, 0x7f},
+ {0xdb, 0x7f},
+ {0xbe, 0x7f},
+ {0xbf, 0x7f},
+ {0xc0, 0xe2},
+ {0xc1, 0xc0},
+ {0xc2, 0x01},
+ {0xc3, 0x4e},
+ {0xc6, 0x85},
+ {0xc7, 0x80},
+ {0xc9, 0xe0},
+ {0xca, 0xe8},
+ {0xcb, 0xf0},
+ {0xcc, 0xd8},
+ {0xcd, 0xf1},
+ {0x4f, 0x98},
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a},
+ {0xff, 0x41}, /* read 41, write ff 00 */
+ {0x41, 0x40}, /* com16 */
+ {0xc5, 0x03},
+ {0x6a, 0x02},
+
+ {0x12, 0x62}, /* com7 - VGA + CIF */
+ {0x36, 0xfa}, /* rsvd36 */
+ {0x69, 0x0a}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c},
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80},
+ {0x03, 0x12}, /* vref */
+ {0x17, 0x16}, /* hstart */
+ {0x18, 0x02}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x3d}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xaa},
+};
+
+static const u8 bridge_init_ov965x_2[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0xda, 0x01},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x3c},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0xa0},
+ {0x5b, 0x78},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_init_ov965x_2[][2] = {
+ {0x3b, 0xc4},
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00}, /* gain */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x03}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x05},
+ {0xc5, 0x07},
+ {0xa2, 0x4b},
+ {0xa3, 0x3e},
+ {0x2d, 0x00},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc0},
+ {0x2d, 0x00},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1},
+ {0x3f, 0x01},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1},
+ {0x4f, 0x98},
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a},
+ {0xff, 0x41}, /* read 41, write ff 00 */
+ {0x41, 0x40}, /* com16 */
+ {0x56, 0x40},
+ {0x55, 0x8f},
+ {0x10, 0x25}, /* aech - exposure high bits */
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+};
+
+static const u8 bridge_start_ov965x[][2] = {
+#if 0
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+#endif
+ {0xc2, 0x4c},
+ {0xc3, 0xf9},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x78},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0x28},
+ {0x5b, 0x1e},
+ {0x35, 0x00},
+ {0xd9, 0x21},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_start_ov965x[][2] = {
+ {0x3b, 0xe4},
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x01}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x02},
+ {0xc5, 0x03},
+ {0xa2, 0x96},
+ {0xa3, 0x7d},
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7},
+ {0x3a, 0x80},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1},
+};
+
+#if 0
+static const u8 sensor_start_ov965x_2[][2] = {
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7},
+ {0x3a, 0x80},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1},
+};
+#endif
+
+static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+ gspca_dev->usb_buf[0] = val;
+ ret = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+ if (ret < 0)
+ PDEBUG(D_ERR, "write failed");
+}
+
+static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ 0x01,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+ PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
+ if (ret < 0)
+ PDEBUG(D_ERR, "read failed");
+ return gspca_dev->usb_buf[0];
+}
+
+/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
+ * (direction and output)? */
+static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
+{
+ u8 data;
+
+ PDEBUG(D_CONF, "led status: %d", status);
+
+ data = ov534_reg_read(gspca_dev, 0x21);
+ data |= 0x80;
+ ov534_reg_write(gspca_dev, 0x21, data);
+
+ data = ov534_reg_read(gspca_dev, 0x23);
+ if (status)
+ data |= 0x80;
+ else
+ data &= ~0x80;
+
+ ov534_reg_write(gspca_dev, 0x23, data);
+
+ if (!status) {
+ data = ov534_reg_read(gspca_dev, 0x21);
+ data &= ~0x80;
+ ov534_reg_write(gspca_dev, 0x21, data);
+ }
+}
+
+static int sccb_check_status(struct gspca_dev *gspca_dev)
+{
+ u8 data;
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
+
+ switch (data) {
+ case 0x00:
+ return 1;
+ case 0x04:
+ return 0;
+ case 0x03:
+ break;
+ default:
+ PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
+ data, i + 1);
+ }
+ }
+ return 0;
+}
+
+static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+{
+ PDEBUG(D_USBO, "reg: 0x%02x, val: 0x%02x", reg, val);
+ ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+ ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
+ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
+
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_reg_write failed");
+}
+
+static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+ ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_reg_read failed 1");
+
+ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_reg_read failed 2");
+
+ return ov534_reg_read(gspca_dev, OV534_REG_READ);
+}
+
+/* output a bridge sequence (reg - val) */
+static void reg_w_array(struct gspca_dev *gspca_dev,
+ const u8 (*data)[2], int len)
+{
+ while (--len >= 0) {
+ ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]);
+ data++;
+ }
+}
+
+/* output a sensor sequence (reg - val) */
+static void sccb_w_array(struct gspca_dev *gspca_dev,
+ const u8 (*data)[2], int len)
+{
+ while (--len >= 0) {
+ if ((*data)[0] != 0xff) {
+ sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]);
+ } else {
+ sccb_reg_read(gspca_dev, (*data)[1]);
+ sccb_reg_write(gspca_dev, 0xff, 0x00);
+ }
+ data++;
+ }
+}
+
/* set framerate */
static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
{
@@ -346,37 +713,15 @@ static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "frame_rate: %d", fr);
}
-/* setup method */
-static void ov534_setup(struct gspca_dev *gspca_dev)
-{
- int i;
-
- /* Initialize bridge chip */
- for (i = 0; i < ARRAY_SIZE(ov534_reg_initdata); i++)
- ov534_reg_write(gspca_dev, ov534_reg_initdata[i][0],
- ov534_reg_initdata[i][1]);
-
- PDEBUG(D_PROBE, "sensor is ov%02x%02x",
- sccb_reg_read(gspca_dev, 0x0a),
- sccb_reg_read(gspca_dev, 0x0b));
-
- ov534_set_led(gspca_dev, 1);
-
- /* Initialize sensor */
- for (i = 0; i < ARRAY_SIZE(ov772x_reg_initdata); i++)
- sccb_reg_write(gspca_dev, ov772x_reg_initdata[i][0],
- ov772x_reg_initdata[i][1]);
-
- ov534_reg_write(gspca_dev, 0xe0, 0x09);
- ov534_set_led(gspca_dev, 0);
-}
-
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
+ struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
+ sd->sensor = id->driver_info;
+
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
@@ -391,26 +736,106 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- ov534_setup(gspca_dev);
- ov534_set_frame_rate(gspca_dev);
+ struct sd *sd = (struct sd *) gspca_dev;
+ u16 sensor_id;
+ static const u8 sensor_addr[2] = {
+ 0x42, /* 0 SENSOR_OV772X */
+ 0x60, /* 1 SENSOR_OV965X */
+ };
+
+ /* reset bridge */
+ ov534_reg_write(gspca_dev, 0xe7, 0x3a);
+ ov534_reg_write(gspca_dev, 0xe0, 0x08);
+ msleep(100);
+
+ /* initialize the sensor address */
+ ov534_reg_write(gspca_dev, OV534_REG_ADDRESS,
+ sensor_addr[sd->sensor]);
+
+ /* reset sensor */
+ sccb_reg_write(gspca_dev, 0x12, 0x80);
+ msleep(10);
+
+ /* probe the sensor */
+ sccb_reg_read(gspca_dev, 0x0a);
+ sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8;
+ sccb_reg_read(gspca_dev, 0x0b);
+ sensor_id |= sccb_reg_read(gspca_dev, 0x0b);
+ PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
+
+ /* initialize */
+ switch (sd->sensor) {
+ case SENSOR_OV772X:
+ reg_w_array(gspca_dev, bridge_init_ov722x,
+ ARRAY_SIZE(bridge_init_ov722x));
+ ov534_set_led(gspca_dev, 1);
+ sccb_w_array(gspca_dev, sensor_init_ov722x,
+ ARRAY_SIZE(sensor_init_ov722x));
+ ov534_reg_write(gspca_dev, 0xe0, 0x09);
+ ov534_set_led(gspca_dev, 0);
+ ov534_set_frame_rate(gspca_dev);
+ break;
+ default:
+/* case SENSOR_OV965X: */
+ reg_w_array(gspca_dev, bridge_init_ov965x,
+ ARRAY_SIZE(bridge_init_ov965x));
+ sccb_w_array(gspca_dev, sensor_init_ov965x,
+ ARRAY_SIZE(sensor_init_ov965x));
+ reg_w_array(gspca_dev, bridge_init_ov965x_2,
+ ARRAY_SIZE(bridge_init_ov965x_2));
+ sccb_w_array(gspca_dev, sensor_init_ov965x_2,
+ ARRAY_SIZE(sensor_init_ov965x_2));
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ ov534_reg_write(gspca_dev, 0xe0, 0x01);
+ ov534_set_led(gspca_dev, 0);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ }
return 0;
}
static int sd_start(struct gspca_dev *gspca_dev)
{
- /* start streaming data */
- ov534_set_led(gspca_dev, 1);
- ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ struct sd *sd = (struct sd *) gspca_dev;
+ switch (sd->sensor) {
+ case SENSOR_OV772X:
+ ov534_set_led(gspca_dev, 1);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ break;
+ default:
+/* case SENSOR_OV965X: */
+#if 0
+ sccb_w_array(gspca_dev, sensor_init_ov965x,
+ ARRAY_SIZE(sensor_init_ov965x));
+#endif
+ reg_w_array(gspca_dev, bridge_start_ov965x,
+ ARRAY_SIZE(bridge_start_ov965x));
+ sccb_w_array(gspca_dev, sensor_start_ov965x,
+ ARRAY_SIZE(sensor_start_ov965x));
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ ov534_set_led(gspca_dev, 1);
+/*fixme: other sensor start omitted*/
+ }
return 0;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- /* stop streaming data */
- ov534_reg_write(gspca_dev, 0xe0, 0x09);
- ov534_set_led(gspca_dev, 0);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+ case SENSOR_OV772X:
+ ov534_reg_write(gspca_dev, 0xe0, 0x09);
+ ov534_set_led(gspca_dev, 0);
+ break;
+ default:
+/* case SENSOR_OV965X: */
+ ov534_reg_write(gspca_dev, 0xe0, 0x01);
+ ov534_set_led(gspca_dev, 0);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ break;
+ }
}
/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
@@ -428,75 +853,75 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
{
struct sd *sd = (struct sd *) gspca_dev;
__u32 this_pts;
- int this_fid;
+ u16 this_fid;
int remaining_len = len;
- __u8 *next_data = data;
-scan_next:
- if (remaining_len <= 0)
- return;
-
- data = next_data;
- len = min(remaining_len, 2048);
- remaining_len -= len;
- next_data += len;
-
- /* Payloads are prefixed with a UVC-style header. We
- consider a frame to start when the FID toggles, or the PTS
- changes. A frame ends when EOF is set, and we've received
- the correct number of bytes. */
-
- /* Verify UVC header. Header length is always 12 */
- if (data[0] != 12 || len < 12) {
- PDEBUG(D_PACK, "bad header");
- goto discard;
- }
+ do {
+ len = min(remaining_len, 2040); /*fixme: was 2048*/
- /* Check errors */
- if (data[1] & UVC_STREAM_ERR) {
- PDEBUG(D_PACK, "payload error");
- goto discard;
- }
-
- /* Extract PTS and FID */
- if (!(data[1] & UVC_STREAM_PTS)) {
- PDEBUG(D_PACK, "PTS not present");
- goto discard;
- }
- this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2];
- this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
-
- /* If PTS or FID has changed, start a new frame. */
- if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
- sd->last_pts = this_pts;
- sd->last_fid = this_fid;
- }
+ /* Payloads are prefixed with a UVC-style header. We
+ consider a frame to start when the FID toggles, or the PTS
+ changes. A frame ends when EOF is set, and we've received
+ the correct number of bytes. */
- /* Add the data from this payload */
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- data + 12, len - 12);
+ /* Verify UVC header. Header length is always 12 */
+ if (data[0] != 12 || len < 12) {
+ PDEBUG(D_PACK, "bad header");
+ goto discard;
+ }
- /* If this packet is marked as EOF, end the frame */
- if (data[1] & UVC_STREAM_EOF) {
- sd->last_pts = 0;
+ /* Check errors */
+ if (data[1] & UVC_STREAM_ERR) {
+ PDEBUG(D_PACK, "payload error");
+ goto discard;
+ }
- if ((frame->data_end - frame->data) !=
- (gspca_dev->width * gspca_dev->height * 2)) {
- PDEBUG(D_PACK, "short frame");
+ /* Extract PTS and FID */
+ if (!(data[1] & UVC_STREAM_PTS)) {
+ PDEBUG(D_PACK, "PTS not present");
goto discard;
}
+ this_pts = (data[5] << 24) | (data[4] << 16)
+ | (data[3] << 8) | data[2];
+ this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
+
+ /* If PTS or FID has changed, start a new frame. */
+ if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ NULL, 0);
+ sd->last_pts = this_pts;
+ sd->last_fid = this_fid;
+ }
- gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
- }
+ /* Add the data from this payload */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data + 12, len - 12);
+
+ /* If this packet is marked as EOF, end the frame */
+ if (data[1] & UVC_STREAM_EOF) {
+ sd->last_pts = 0;
+
+ if (frame->data_end - frame->data !=
+ gspca_dev->width * gspca_dev->height * 2) {
+ PDEBUG(D_PACK, "short frame");
+ goto discard;
+ }
- /* Done this payload */
- goto scan_next;
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ NULL, 0);
+ }
+
+ /* Done this payload */
+ goto scan_next;
discard:
- /* Discard data until a new frame starts. */
- gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
- goto scan_next;
+ /* Discard data until a new frame starts. */
+ gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
+
+scan_next:
+ remaining_len -= len;
+ data += len;
+ } while (remaining_len > 0);
}
/* get stream parameters (framerate) */
@@ -556,11 +981,11 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
#if 0
- /* these two are not supported yet, different sensors */
- {USB_DEVICE(0x06f8, 0x3002)}, /* Hercules Blog Webcam */
- {USB_DEVICE(0x06f8, 0x3003)}, /* Hercules Dualpix HD Weblog */
+ /* not supported yet */
+ {USB_DEVICE(0x06f8, 0x3002), .driver_info = SENSOR_unknown},
#endif
- {USB_DEVICE(0x1415, 0x2000)}, /* Sony HD Eye for PS3 (SLEH 00201) */
+ {USB_DEVICE(0x06f8, 0x3003), .driver_info = SENSOR_OV965X},
+ {USB_DEVICE(0x1415, 0x2000), .driver_info = SENSOR_OV772X},
{}
};
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index 36d6f50be..c3959f00a 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "sonixj"
#include "gspca.h"
-#define QUANT_VAL 4 /* quantization table */
#include "jpeg.h"
#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
@@ -47,6 +46,13 @@ struct sd {
u8 gamma;
u8 vflip; /* ov7630/ov7648 only */
u8 infrared; /* mt9v111 only */
+ u8 quality; /* image quality */
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
+ u8 jpegqual; /* webcam quality */
+
+ u8 reg18;
s8 ag_cnt;
#define AG_CNT_START 13
@@ -68,6 +74,8 @@ struct sd {
#define SENSOR_OV7660 7
#define SENSOR_SP80708 8
u8 i2c_base;
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -867,25 +875,6 @@ static const u8 sp80708_sensor_init[][8] = {
{}
};
-static const u8 qtable4[] = {
- 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06,
- 0x06, 0x06, 0x08, 0x06, 0x06, 0x08, 0x0a, 0x11,
- 0x0a, 0x0a, 0x08, 0x08, 0x0a, 0x15, 0x0f, 0x0f,
- 0x0c, 0x11, 0x19, 0x15, 0x19, 0x19, 0x17, 0x15,
- 0x17, 0x17, 0x1b, 0x1d, 0x25, 0x21, 0x1b, 0x1d,
- 0x23, 0x1d, 0x17, 0x17, 0x21, 0x2e, 0x21, 0x23,
- 0x27, 0x29, 0x2c, 0x2c, 0x2c, 0x19, 0x1f, 0x30,
- 0x32, 0x2e, 0x29, 0x32, 0x25, 0x29, 0x2c, 0x29,
- 0x06, 0x08, 0x08, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
- 0x0a, 0x13, 0x29, 0x1b, 0x17, 0x1b, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29
-};
-
/* read <len> bytes to gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
u16 value, int len)
@@ -1325,6 +1314,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
else
sd->vflip = 1;
sd->infrared = INFRARED_DEF;
+ sd->quality = QUALITY_DEF;
+ sd->jpegqual = 80;
gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
return 0;
@@ -1642,12 +1633,49 @@ static void setinfrared(struct sd *sd)
#endif
}
+static void setjpegqual(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, sc;
+
+ if (sd->jpegqual < 50)
+ sc = 5000 / sd->jpegqual;
+ else
+ sc = 200 - sd->jpegqual * 2;
+#if USB_BUF_SZ < 64
+#error "No room enough in usb_buf for quantization table"
+#endif
+ for (i = 0; i < 64; i++)
+ gspca_dev->usb_buf[i] =
+ (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x0100, 0,
+ gspca_dev->usb_buf, 64,
+ 500);
+ for (i = 0; i < 64; i++)
+ gspca_dev->usb_buf[i] =
+ (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x0140, 0,
+ gspca_dev->usb_buf, 64,
+ 500);
+
+ sd->reg18 ^= 0x40;
+ reg_w1(gspca_dev, 0x18, sd->reg18);
+}
+
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 reg1, reg17, reg18;
+ u8 reg1, reg17;
const u8 *sn9c1xx;
int mode;
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
@@ -1656,6 +1684,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
static const u8 CE_ov76xx[] =
{ 0x32, 0xdd, 0x32, 0xdd };
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
sn9c1xx = sn_tb[(int) sd->sensor];
configure_gpio(gspca_dev, sn9c1xx);
@@ -1816,13 +1850,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* here change size mode 0 -> VGA; 1 -> CIF */
- reg18 = sn9c1xx[0x18] | (mode << 4);
- reg_w1(gspca_dev, 0x18, reg18 | 0x40);
-
- reg_w(gspca_dev, 0x0100, qtable4, 0x40);
- reg_w(gspca_dev, 0x0140, qtable4 + 0x40, 0x40);
-
- reg_w1(gspca_dev, 0x18, reg18);
+ sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
+ reg_w1(gspca_dev, 0x18, sd->reg18);
+ setjpegqual(gspca_dev);
reg_w1(gspca_dev, 0x17, reg17);
reg_w1(gspca_dev, 0x01, reg1);
@@ -1884,6 +1914,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0xf1, 0x00);
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1967,7 +2004,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
if (gspca_dev->last_packet_type == LAST_PACKET) {
/* put the JPEG 422 header */
- jpeg_put_header(gspca_dev, frame, 0x21);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
}
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
@@ -2134,6 +2172,34 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -2143,8 +2209,11 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
@@ -2159,9 +2228,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
#endif
{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
-#endif
{USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c
index 94caba63b..8cfb7cad9 100644
--- a/linux/drivers/media/video/gspca/spca500.c
+++ b/linux/drivers/media/video/gspca/spca500.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "spca500"
#include "gspca.h"
-#define QUANT_VAL 5 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -39,6 +38,10 @@ struct sd {
unsigned char brightness;
unsigned char contrast;
unsigned char colors;
+ u8 quality;
+#define QUALITY_MIN 70
+#define QUALITY_MAX 95
+#define QUALITY_DEF 85
char subtype;
#define AgfaCl20 0
@@ -56,6 +59,8 @@ struct sd {
#define Optimedia 12
#define PalmPixDC85 13
#define ToptroIndus 14
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -657,6 +662,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -682,6 +688,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
__u8 Data;
__u8 xmult, ymult;
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
if (sd->subtype == LogitechClickSmart310) {
xmult = 0x16;
ymult = 0x12;
@@ -897,6 +909,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0]);
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -917,7 +936,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
ffd9, 2);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
data += SPCA500_OFFSET_DATA;
len -= SPCA500_OFFSET_DATA;
@@ -1021,6 +1041,34 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -1030,7 +1078,10 @@ static struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/sq905.c b/linux/drivers/media/video/gspca/sq905.c
index dafaed69e..04e3ae57a 100644
--- a/linux/drivers/media/video/gspca/sq905.c
+++ b/linux/drivers/media/video/gspca/sq905.c
@@ -60,24 +60,28 @@ MODULE_LICENSE("GPL");
#define SQ905_PING 0x07 /* when reading an "idling" command */
#define SQ905_READ_DONE 0xc0 /* ack bulk read completed */
+/* Any non-zero value in the bottom 2 bits of the 2nd byte of
+ * the ID appears to indicate the camera can do 640*480. If the
+ * LSB of that byte is set the image is just upside down, otherwise
+ * it is rotated 180 degrees. */
+#define SQ905_HIRES_MASK 0x00000300
+#define SQ905_ORIENTATION_MASK 0x00000100
+
/* Some command codes. These go in the "index" slot. */
#define SQ905_ID 0xf0 /* asks for model string */
#define SQ905_CONFIG 0x20 /* gets photo alloc. table, not used here */
#define SQ905_DATA 0x30 /* accesses photo data, not used here */
#define SQ905_CLEAR 0xa0 /* clear everything */
-#define SQ905_CAPTURE_LOW 0x60 /* Starts capture at 160x120 */
-#define SQ905_CAPTURE_MED 0x61 /* Starts capture at 320x240 */
+#define SQ905_CAPTURE_LOW 0x60 /* Starts capture at 160x120 */
+#define SQ905_CAPTURE_MED 0x61 /* Starts capture at 320x240 */
+#define SQ905_CAPTURE_HIGH 0x62 /* Starts capture at 640x480 (some cams only) */
/* note that the capture command also controls the output dimensions */
-/* 0x60 -> 160x120, 0x61 -> 320x240 0x62 -> 640x480 depends on camera */
-/* 0x62 is not correct, at least for some cams. Should be 0x63 ? */
/* Structure to hold all of our device specific stuff */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- u8 cam_type;
-
/*
* Driver stuff
*/
@@ -85,33 +89,24 @@ struct sd {
struct workqueue_struct *work_thread;
};
-/* The driver only supports 320x240 so far. */
-static struct v4l2_pix_format sq905_mode[1] = {
+static struct v4l2_pix_format sq905_mode[] = {
+ { 160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
{ 320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240,
.colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ { 640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0}
};
-struct cam_type {
- u32 ident_word;
- char *name;
- struct v4l2_pix_format *min_mode;
- u8 num_modes;
- u8 sensor_flags;
-};
-
-#define SQ905_FLIP_HORIZ (1 << 0)
-#define SQ905_FLIP_VERT (1 << 1)
-
-/* Last entry is default if nothing else matches */
-static struct cam_type cam_types[] = {
- { 0x19010509, "PocketCam", &sq905_mode[0], 1, SQ905_FLIP_HORIZ },
- { 0x32010509, "Magpix", &sq905_mode[0], 1, SQ905_FLIP_HORIZ },
- { 0, "Default", &sq905_mode[0], 1, SQ905_FLIP_HORIZ | SQ905_FLIP_VERT }
-};
-
/*
* Send a command to the camera.
*/
@@ -221,6 +216,7 @@ static void sq905_dostream(struct work_struct *work)
int header_read; /* true if we have already read the frame header. */
int discarding; /* true if we failed to get space for frame. */
int packet_type;
+ int frame_sz;
int ret;
u8 *data;
u8 *buffer;
@@ -232,6 +228,9 @@ static void sq905_dostream(struct work_struct *work)
goto quit_stream;
}
+ frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage
+ + FRAME_HEADER_LEN;
+
while (gspca_dev->present && gspca_dev->streaming) {
/* Need a short delay to ensure streaming flag was set by
* gspca and to make sure gspca can grab the mutex. */
@@ -240,7 +239,7 @@ static void sq905_dostream(struct work_struct *work)
/* request some data and then read it until we have
* a complete frame. */
- bytes_left = sq905_mode[0].sizeimage + FRAME_HEADER_LEN;
+ bytes_left = frame_sz;
header_read = 0;
discarding = 0;
@@ -272,11 +271,19 @@ static void sq905_dostream(struct work_struct *work)
packet_type = INTER_PACKET;
}
frame = gspca_get_i_frame(gspca_dev);
- if (frame && !discarding)
- gspca_frame_add(gspca_dev, packet_type,
+ if (frame && !discarding) {
+ frame = gspca_frame_add(gspca_dev, packet_type,
frame, data, data_len);
- else
+ /* If entire frame fits in one packet we still
+ need to add a LAST_PACKET */
+ if (packet_type == FIRST_PACKET &&
+ bytes_left == 0)
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame, data, 0);
+ } else {
discarding = 1;
+ }
}
/* acknowledge the frame */
mutex_lock(&gspca_dev->usb_lock);
@@ -301,8 +308,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam = &gspca_dev->cam;
struct sd *dev = (struct sd *) gspca_dev;
- cam->cam_mode = sq905_mode;
- cam->nmodes = 1;
/* We don't use the buffer gspca allocates so make it small. */
cam->bulk_size = 64;
@@ -328,7 +333,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- struct sd *dev = (struct sd *) gspca_dev;
u32 ident;
int ret;
@@ -344,17 +348,18 @@ static int sd_init(struct gspca_dev *gspca_dev)
ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4);
if (ret < 0)
return ret;
- /* usb_buf is allocated with kmalloc so is aligned. */
- ident = le32_to_cpup((u32 *)gspca_dev->usb_buf);
+ /* usb_buf is allocated with kmalloc so is aligned.
+ * Camera model number is the right way round if we assume this
+ * reverse engineered ID is supposed to be big endian. */
+ ident = be32_to_cpup((__be32 *)gspca_dev->usb_buf);
ret = sq905_command(gspca_dev, SQ905_CLEAR);
if (ret < 0)
return ret;
- dev->cam_type = 0;
- while (dev->cam_type < ARRAY_SIZE(cam_types) - 1 &&
- ident != cam_types[dev->cam_type].ident_word)
- dev->cam_type++;
- PDEBUG(D_CONF, "SQ905 camera %s, ID %08x detected",
- cam_types[dev->cam_type].name, ident);
+ PDEBUG(D_CONF, "SQ905 camera ID %08x detected", ident);
+ gspca_dev->cam.cam_mode = sq905_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(sq905_mode);
+ if (!(ident & SQ905_HIRES_MASK))
+ gspca_dev->cam.nmodes--;
return 0;
}
@@ -365,12 +370,25 @@ static int sd_start(struct gspca_dev *gspca_dev)
int ret;
/* "Open the shutter" and set size, to start capture */
- ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED);
+ switch (gspca_dev->curr_mode) {
+ default:
+/* case 2: */
+ PDEBUG(D_STREAM, "Start streaming at high resolution");
+ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_HIGH);
+ break;
+ case 1:
+ PDEBUG(D_STREAM, "Start streaming at medium resolution");
+ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED);
+ break;
+ case 0:
+ PDEBUG(D_STREAM, "Start streaming at low resolution");
+ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_LOW);
+ }
+
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);
diff --git a/linux/drivers/media/video/gspca/sq905c.c b/linux/drivers/media/video/gspca/sq905c.c
new file mode 100644
index 000000000..0bcb74a1b
--- /dev/null
+++ b/linux/drivers/media/video/gspca/sq905c.c
@@ -0,0 +1,328 @@
+/*
+ * SQ905C subdriver
+ *
+ * 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
+ */
+
+/*
+ *
+ * This driver uses work done in
+ * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore.
+ *
+ * This driver has also used as a base the sq905c driver
+ * and may contain code fragments from it.
+ */
+
+#define MODULE_NAME "sq905c"
+
+#include <linux/workqueue.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define SQ905C_CMD_TIMEOUT 500
+#define SQ905C_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define SQ905C_MAX_TRANSFER 0x8000
+
+#define FRAME_HEADER_LEN 0x50
+
+/* Commands. These go in the "value" slot. */
+#define SQ905C_CLEAR 0xa0 /* clear everything */
+#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */
+#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */
+#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */
+
+/* For capture, this must go in the "index" slot. */
+#define SQ905C_CAPTURE_INDEX 0x110f
+
+/* 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;
+};
+
+/*
+ * Most of these cameras will do 640x480 and 320x240. 160x120 works
+ * in theory but gives very poor output. Therefore, not supported.
+ * The 0x2770:0x9050 cameras have max resolution of 320x240.
+ */
+static struct v4l2_pix_format sq905c_mode[] = {
+ { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0}
+};
+
+/* Send a command to the camera. */
+static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
+{
+ int ret;
+
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_SYNCH_FRAME, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ command, index, NULL, 0,
+ SQ905C_CMD_TIMEOUT);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* 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 sq905c_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 bytes_left; /* bytes remaining in current frame. */
+ int data_len; /* size to use for the next read. */
+ int act_len;
+ int discarding = 0; /* true if we failed to get space for frame. */
+ int packet_type;
+ int ret;
+ u8 *buffer;
+
+ buffer = kmalloc(SQ905C_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;
+ /* Request the header, which tells the size to download */
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+ buffer, FRAME_HEADER_LEN, &act_len,
+ SQ905C_DATA_TIMEOUT);
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for header",
+ act_len, FRAME_HEADER_LEN);
+ if (ret < 0 || act_len < FRAME_HEADER_LEN)
+ goto quit_stream;
+ /* size is read from 4 bytes starting 0x40, little endian */
+ bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16)
+ |(buffer[0x43]<<24);
+ PDEBUG(D_STREAM, "bytes_left = 0x%x", bytes_left);
+ /* We keep the header. It has other information, too. */
+ packet_type = FIRST_PACKET;
+ frame = gspca_get_i_frame(gspca_dev);
+ if (frame && !discarding) {
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer, FRAME_HEADER_LEN);
+ } else
+ discarding = 1;
+ while (bytes_left > 0) {
+ data_len = bytes_left > SQ905C_MAX_TRANSFER ?
+ SQ905C_MAX_TRANSFER : bytes_left;
+ if (!gspca_dev->present)
+ goto quit_stream;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+ buffer, data_len, &act_len,
+ SQ905C_DATA_TIMEOUT);
+ if (ret < 0 || act_len < data_len)
+ goto quit_stream;
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for frame",
+ data_len, bytes_left);
+ bytes_left -= data_len;
+ if (bytes_left == 0)
+ packet_type = LAST_PACKET;
+ else
+ packet_type = INTER_PACKET;
+ frame = gspca_get_i_frame(gspca_dev);
+ if (frame && !discarding)
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer, data_len);
+ else
+ discarding = 1;
+ }
+ }
+quit_stream:
+ mutex_lock(&gspca_dev->usb_lock);
+ if (gspca_dev->present)
+ sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+ 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;
+
+ PDEBUG(D_PROBE,
+ "SQ9050 camera detected"
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ cam->cam_mode = sq905c_mode;
+ cam->nmodes = 2;
+ if (id->idProduct == 0x9050)
+ cam->nmodes = 1;
+ /* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk_size = 32;
+ INIT_WORK(&dev->work_struct, sq905c_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 sq905c_dostream to finish */
+ destroy_workqueue(dev->work_thread);
+ dev->work_thread = NULL;
+ mutex_lock(&gspca_dev->usb_lock);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ /* connect to the camera and reset it. */
+ ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+ return ret;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+ int ret;
+
+ dev->cap_mode = gspca_dev->cam.cam_mode;
+ /* "Open the shutter" and set size, to start capture */
+ switch (gspca_dev->width) {
+ case 640:
+ PDEBUG(D_STREAM, "Start streaming at high resolution");
+ dev->cap_mode++;
+ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI,
+ SQ905C_CAPTURE_INDEX);
+ break;
+ default: /* 320 */
+ PDEBUG(D_STREAM, "Start streaming at medium resolution");
+ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED,
+ SQ905C_CAPTURE_INDEX);
+ }
+
+ 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(0x2770, 0x905c)},
+ {USB_DEVICE(0x2770, 0x9050)},
+ {USB_DEVICE(0x2770, 0x913d)},
+ {}
+};
+
+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/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c
index d1d54edd8..f25be20cf 100644
--- a/linux/drivers/media/video/gspca/stk014.c
+++ b/linux/drivers/media/video/gspca/stk014.c
@@ -21,8 +21,6 @@
#define MODULE_NAME "stk014"
#include "gspca.h"
-#define QUANT_VAL 7 /* quantization table */
- /* <= 4 KO - 7: good (enough!) */
#include "jpeg.h"
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
@@ -37,6 +35,12 @@ struct sd {
unsigned char contrast;
unsigned char colors;
unsigned char lightfreq;
+ u8 quality;
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -300,6 +304,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->lightfreq = FREQ_DEF;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -323,8 +328,15 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
int ret, value;
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
/* work on alternate 1 */
usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
@@ -396,11 +408,19 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "camera stopped");
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
static unsigned char ffd9[] = {0xff, 0xd9};
/* a frame starts with:
@@ -417,7 +437,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
ffd9, 2);
/* put the JPEG 411 header */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
/* beginning of the frame */
#define STKHDRSZ 12
@@ -517,6 +538,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -526,8 +575,11 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c
index fba6f98d1..428b1e2b7 100644
--- a/linux/drivers/media/video/gspca/sunplus.c
+++ b/linux/drivers/media/video/gspca/sunplus.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "sunplus"
#include "gspca.h"
-#define QUANT_VAL 5 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -40,6 +39,10 @@ struct sd {
unsigned char contrast;
unsigned char colors;
unsigned char autogain;
+ u8 quality;
+#define QUALITY_MIN 70
+#define QUALITY_MAX 95
+#define QUALITY_DEF 85
char bridge;
#define BRIDGE_SPCA504 0
@@ -52,6 +55,8 @@ struct sd {
#define LogitechClickSmart420 2
#define LogitechClickSmart820 3
#define MegapixV4 4
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -883,6 +888,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
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;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -999,6 +1005,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
__u8 i;
__u8 info[6];
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
if (sd->bridge == BRIDGE_SPCA504B)
spca504B_setQtable(gspca_dev);
spca504B_SetSizeType(gspca_dev);
@@ -1108,6 +1120,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
}
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -1184,7 +1203,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
ffd9, 2);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
}
/* add 0x00 after 0xff */
@@ -1333,6 +1353,34 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -1342,7 +1390,10 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c
index f60a4c21a..f6ff3e1ea 100644
--- a/linux/drivers/media/video/gspca/t613.c
+++ b/linux/drivers/media/video/gspca/t613.c
@@ -495,7 +495,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
};
reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
- msleep(5);
+ msleep(100);
i = 4;
while (--i > 0) {
byte = reg_r(gspca_dev, 0x0060);
@@ -639,7 +639,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
u16 reg80, reg8e;
static const u8 read_indexs[] =
- { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+ { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
static const u8 n1[] =
{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
@@ -679,7 +679,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
sensor_id = (reg_r(gspca_dev, 0x06) << 8)
| reg_r(gspca_dev, 0x07);
- switch (sensor_id) {
+ switch (sensor_id & 0xff0f) {
case 0x0801:
PDEBUG(D_PROBE, "sensor tas5130a");
sd->sensor = SENSOR_TAS5130A;
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
index 72cbf56c9..772d18e70 100644
--- a/linux/drivers/media/video/gspca/vc032x.c
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -37,18 +37,21 @@ struct sd {
__u8 lightfreq;
__u8 sharpness;
+ u8 image_offset;
+
char bridge;
#define BRIDGE_VC0321 0
#define BRIDGE_VC0323 1
char sensor;
#define SENSOR_HV7131R 0
#define SENSOR_MI0360 1
-#define SENSOR_MI1320 2
-#define SENSOR_MI1310_SOC 3
-#define SENSOR_OV7660 4
-#define SENSOR_OV7670 5
-#define SENSOR_PO1200 6
-#define SENSOR_PO3130NC 7
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_MI1320 3
+#define SENSOR_MI1320_SOC 4
+#define SENSOR_OV7660 5
+#define SENSOR_OV7670 6
+#define SENSOR_PO1200 7
+#define SENSOR_PO3130NC 8
};
/* V4L2 controls supported by the driver */
@@ -149,13 +152,50 @@ 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, /* mi1310_soc only */
+ {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi13x0_soc only */
.bytesperline = 1280,
.sizeimage = 1280 * 1024 * 1 / 4 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
};
-
+static const struct v4l2_pix_format bi_mode[] = {
+/*fixme: jeg does not work
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 5},
+*/
+ {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 4},
+/*
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+*/
+ {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+/*
+ {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024 * 1 / 4 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+*/
+ {1280, 1024, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
static const struct v4l2_pix_format svga_mode[] = {
{800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 800,
@@ -891,6 +931,722 @@ static const __u8 mi1320_initQVGA_data[][4] = {
{}
};
+static const u8 mi1320_soc_InitVGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 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},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {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},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const u8 mi1320_soc_InitVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 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},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x05, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 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, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {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},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const u8 mi1320_soc_InitQVGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 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},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {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},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const u8 mi1320_soc_InitQVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 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},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {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, 0x05, 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},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {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},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const u8 mi1320_soc_InitSXGA_JPG[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x05, 0xcc},
+ {0xb6, 0x02, 0x00, 0xcc},
+ {0xb6, 0x05, 0x04, 0xcc},
+ {0xb6, 0x04, 0x00, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x0a, 0xcc},
+ {0xb6, 0x17, 0x00, 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},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {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},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb},
+ {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x64, 0x5e, 0x1c, 0xbb},
+ {0x2f, 0x90, 0x00, 0xbb},
+ {}
+};
+static const u8 mi1320_soc_InitSXGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {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},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb},
+ {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x64, 0x5e, 0x1c, 0xbb},
+ {}
+};
static const __u8 po3130_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
@@ -1903,26 +2659,55 @@ static const __u8 po1200_initVGA_data[][4] = {
};
struct sensor_info {
- int sensorId;
- __u8 I2cAdd;
- __u8 IdAdd;
- __u16 VpId;
- __u8 m1;
- __u8 m2;
- __u8 op;
- };
+ s8 sensorId;
+ u8 I2cAdd;
+ u8 IdAdd;
+ u16 VpId;
+ u8 m1;
+ u8 m2;
+ u8 op;
+};
static const struct sensor_info sensor_info_data[] = {
/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+#if 1
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+ {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
+/* (tested in vc032x_probe_sensor) */
+/* {-1, 0x80 | 0x20, 0x83, 0x0000, 0x24, 0x25, 0x01}, */
+ {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+ {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+/* (tested in vc032x_probe_sensor) */
+/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+ {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+ {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
+ {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
+ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
+/* {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, */
+ {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
+ {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+ {-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01},
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+ {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
+ {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01},
+/*fixme: previously detected?*/
+ {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
+/*fixme: not in the ms-win probe - may be found before?*/
+ {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+#else
{SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
{SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
{SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
- {SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+ {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
{SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
{SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
/* (tested in vc032x_probe_sensor) */
/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
{SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+#endif
};
/* read 'len' bytes in gspca_dev->usb_buf */
@@ -1957,7 +2742,7 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
u16 address)
{
struct usb_device *dev = gspca_dev->dev;
- __u8 ldata, mdata, hdata;
+ u8 ldata, mdata, hdata;
int retry = 50;
reg_r(gspca_dev, 0xa1, 0xb33f, 1);
@@ -1970,9 +2755,11 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
reg_w(dev, 0xa0, 0x02, 0xb339);
do {
- msleep(8);
reg_r(gspca_dev, 0xa1, 0xb33b, 1);
- } while (retry-- && gspca_dev->usb_buf[0]);
+ if (gspca_dev->usb_buf[0] == 0x00)
+ break;
+ msleep(40);
+ } while (--retry >= 0);
reg_r(gspca_dev, 0xa1, 0xb33e, 1);
ldata = gspca_dev->usb_buf[0];
@@ -1993,7 +2780,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
int i;
- __u16 value;
+ u16 value;
const struct sensor_info *ptsensor_info;
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
@@ -2008,45 +2795,40 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
- if (value == ptsensor_info->VpId)
- return ptsensor_info->sensorId;
-
- /* special case for MI0360 */
- if (ptsensor_info->sensorId == SENSOR_MI1310_SOC
- && value == 0x8243)
- return SENSOR_MI0360;
+ if (value == 0 && ptsensor_info->IdAdd == 0x82)
+ value = read_sensor_register(gspca_dev, 0x83);
+ if (value != 0) {
+ PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)",
+ value, i);
+ if (value == ptsensor_info->VpId)
+ return ptsensor_info->sensorId;
+
+ switch (value) {
+ case 0x7673:
+ return SENSOR_OV7670;
+ case 0x8243:
+ return SENSOR_MI0360;
+ }
+/*fixme: should return here*/
+ }
}
return -1;
}
static void i2c_write(struct gspca_dev *gspca_dev,
- __u8 reg, const __u8 *val, __u8 size)
+ u8 reg, const u8 *val,
+ u8 size) /* 1 or 2 */
{
struct usb_device *dev = gspca_dev->dev;
int retry;
-#ifdef GSPCA_DEBUG
- if (size > 3 || size < 1)
- return;
-#endif
reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
reg_w(dev, 0xa0, size, 0xb334);
reg_w(dev, 0xa0, reg, 0xb33a);
- switch (size) {
- case 1:
- reg_w(dev, 0xa0, val[0], 0xb336);
- break;
- case 2:
- reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ if (size > 1)
reg_w(dev, 0xa0, val[1], 0xb337);
- break;
- default:
-/* case 3: */
- reg_w(dev, 0xa0, val[0], 0xb336);
- reg_w(dev, 0xa0, val[1], 0xb337);
- reg_w(dev, 0xa0, val[2], 0xb338);
- break;
- }
reg_w(dev, 0xa0, 0x01, 0xb339);
retry = 4;
do {
@@ -2141,6 +2923,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
case SENSOR_MI1320:
PDEBUG(D_PROBE, "Find Sensor MI1320");
break;
+ case SENSOR_MI1320_SOC:
+ PDEBUG(D_PROBE, "Find Sensor MI1320_SOC");
+ break;
case SENSOR_OV7660:
PDEBUG(D_PROBE, "Find Sensor OV7660");
break;
@@ -2160,15 +2945,23 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = vc0321_mode;
cam->nmodes = ARRAY_SIZE(vc0321_mode);
} else {
- if (sensor != SENSOR_PO1200) {
- cam->cam_mode = vc0323_mode;
- if (sd->sensor != SENSOR_MI1310_SOC)
- cam->nmodes = ARRAY_SIZE(vc0323_mode);
- else /* no SXGA */
- cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
- } else {
+ switch (sensor) {
+ case SENSOR_PO1200:
cam->cam_mode = svga_mode;
cam->nmodes = ARRAY_SIZE(svga_mode);
+ break;
+ case SENSOR_MI1310_SOC:
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode);
+ break;
+ case SENSOR_MI1320_SOC:
+ cam->cam_mode = bi_mode;
+ cam->nmodes = ARRAY_SIZE(bi_mode);
+ break;
+ default:
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
+ break;
}
}
@@ -2271,6 +3064,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
const __u8 *GammaT = NULL;
const __u8 *MatrixT = NULL;
int mode;
+ static const u8 (*mi1320_soc_init[])[4] = {
+ mi1320_soc_InitSXGA,
+ mi1320_soc_InitSXGA_JPG,
+ mi1320_soc_InitVGA,
+ mi1320_soc_InitVGA_JPG,
+ mi1320_soc_InitQVGA,
+ mi1320_soc_InitQVGA_JPG
+ };
/* Assume start use the good resolution from gspca_dev->mode */
if (sd->bridge == BRIDGE_VC0321) {
@@ -2278,6 +3079,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+ sd->image_offset = 46;
+ } else {
+ if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
+ == V4L2_PIX_FMT_JPEG)
+ sd->image_offset = 0;
+ else
+ sd->image_offset = 32;
}
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
@@ -2316,7 +3124,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
case SENSOR_MI1310_SOC:
GammaT = mi1320_gamma;
- MatrixT = mi0360_matrix;
+ MatrixT = mi1320_matrix;
switch (mode) {
case 1:
init = mi1310_socinitQVGA_JPG; /* 320x240 */
@@ -2325,7 +3133,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
init = mi1310_socinitVGA_JPG; /* 640x480 */
break;
default:
- init = mi1310_soc_InitSXGA_JPG; /* 1280xq024 */
+ init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */
break;
}
break;
@@ -2337,6 +3145,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
else
init = mi1320_initVGA_data; /* 640x480 */
break;
+ case SENSOR_MI1320_SOC:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+ init = mi1320_soc_init[mode];
+ break;
case SENSOR_PO3130NC:
GammaT = po3130_gamma;
MatrixT = po3130_matrix;
@@ -2407,12 +3220,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
"vc032x header packet found len %d", len);
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, 0);
- if (sd->bridge == BRIDGE_VC0321) {
-#define VCHDRSZ 46
- data += VCHDRSZ;
- len -= VCHDRSZ;
-#undef VCHDRSZ
- }
+ data += sd->image_offset;
+ len -= sd->image_offset;
gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
data, len);
return;
@@ -2545,6 +3354,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{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},
{}
diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c
index ad385b9a0..a90b3b0d4 100644
--- a/linux/drivers/media/video/gspca/zc3xx.c
+++ b/linux/drivers/media/video/gspca/zc3xx.c
@@ -23,6 +23,7 @@
#define MODULE_NAME "zc3xx"
#include "gspca.h"
+#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
"Serge A. Suchkov <Serge.A.S@tochka.ru>");
@@ -32,7 +33,6 @@ MODULE_LICENSE("GPL");
static int force_sensor = -1;
#define QUANT_VAL 1 /* quantization table */
-#include "jpeg.h"
#include "zc3xx-reg.h"
/* specific webcam descriptor */
@@ -45,6 +45,10 @@ struct sd {
__u8 autogain;
__u8 lightfreq;
__u8 sharpness;
+ u8 quality; /* image quality */
+#define QUALITY_MIN 40
+#define QUALITY_MAX 60
+#define QUALITY_DEF 50
signed char sensor; /* Type of image sensor chip */
/* !! values used in different tables */
@@ -69,6 +73,8 @@ struct sd {
#define SENSOR_TAS5130C_VF0250 17
#define SENSOR_MAX 18
unsigned short chip_revision;
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -7206,6 +7212,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->gamma = gamma[(int) sd->sensor];
sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+ sd->quality = QUALITY_DEF;
switch (sd->sensor) {
case SENSOR_GC0305:
@@ -7261,6 +7268,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* 17 */
};
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
zc3_init = init_tb[(int) sd->sensor][mode];
switch (sd->sensor) {
@@ -7398,6 +7411,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ kfree(sd->jpeg_hdr);
if (!gspca_dev->present)
return;
send_unknown(gspca_dev->dev, sd->sensor);
@@ -7408,12 +7422,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data,
int len)
{
+ struct sd *sd = (struct sd *) gspca_dev;
if (data[0] == 0xff && data[1] == 0xd8) { /* start of frame */
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, 0);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x21);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
+
/* remove the webcam's header:
* ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
* - 'ss ss' is the frame sequence number (BE)
@@ -7555,6 +7572,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
@@ -7565,6 +7610,8 @@ static const struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
static const __devinitdata struct usb_device_id device_table[] = {
@@ -7615,7 +7662,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x055f, 0xd004)},
{USB_DEVICE(0x0698, 0x2003)},
{USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106},
- {USB_DEVICE(0x0ac8, 0x0302)},
+ {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x0ac8, 0x301b)},
{USB_DEVICE(0x0ac8, 0x303b)},
{USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},
diff --git a/linux/drivers/media/video/hdpvr/Kconfig b/linux/drivers/media/video/hdpvr/Kconfig
new file mode 100644
index 000000000..de247f3c7
--- /dev/null
+++ b/linux/drivers/media/video/hdpvr/Kconfig
@@ -0,0 +1,10 @@
+
+config VIDEO_HDPVR
+ tristate "Hauppauge HD PVR support"
+ depends on VIDEO_DEV
+ ---help---
+ This is a video4linux driver for Hauppauge's HD PVR USB device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hdpvr
+
diff --git a/linux/drivers/media/video/hdpvr/Makefile b/linux/drivers/media/video/hdpvr/Makefile
new file mode 100644
index 000000000..e0230fcb2
--- /dev/null
+++ b/linux/drivers/media/video/hdpvr/Makefile
@@ -0,0 +1,9 @@
+hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o
+
+hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o
+
+obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/linux/drivers/media/video/hdpvr/hdpvr-control.c b/linux/drivers/media/video/hdpvr/hdpvr-control.c
new file mode 100644
index 000000000..06791749d
--- /dev/null
+++ b/linux/drivers/media/video/hdpvr/hdpvr-control.c
@@ -0,0 +1,201 @@
+/*
+ * Hauppauge HD PVR USB driver - video 4 linux 2 interface
+ *
+ * Copyright (C) 2008 Janne Grunau (j@jannau.net)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+
+#include "hdpvr.h"
+
+
+int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
+{
+ int ret;
+ char request_type = 0x38, snd_request = 0x01;
+
+ msleep(10);
+
+ mutex_lock(&dev->usbc_mutex);
+ dev->usbc_buf[0] = valbuf;
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ snd_request, 0x00 | request_type,
+ value, CTRL_DEFAULT_INDEX,
+ dev->usbc_buf, 1, 10000);
+
+ mutex_unlock(&dev->usbc_mutex);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "config call request for value 0x%x returned %d\n", value,
+ ret);
+
+ return ret < 0 ? ret : 0;
+}
+
+struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
+{
+ struct hdpvr_video_info *vidinf = NULL;
+#ifdef HDPVR_DEBUG
+ char print_buf[15];
+#endif
+ int ret;
+
+ vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL);
+ if (!vidinf) {
+ v4l2_err(&dev->v4l2_dev, "out of memory\n");
+ goto err;
+ }
+
+ mutex_lock(&dev->usbc_mutex);
+ ret = usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ 0x81, 0x80 | 0x38,
+ 0x1400, 0x0003,
+ dev->usbc_buf, 5,
+ 1000);
+ if (ret == 5) {
+ vidinf->width = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
+ vidinf->height = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
+ vidinf->fps = dev->usbc_buf[4];
+ }
+
+#ifdef HDPVR_DEBUG
+ if (hdpvr_debug & MSG_INFO) {
+ hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
+ sizeof(print_buf), 0);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "get video info returned: %d, %s\n", ret, print_buf);
+ }
+#endif
+ mutex_unlock(&dev->usbc_mutex);
+
+ if (!vidinf->width || !vidinf->height || !vidinf->fps) {
+ kfree(vidinf);
+ vidinf = NULL;
+ }
+err:
+ return vidinf;
+}
+
+int get_input_lines_info(struct hdpvr_device *dev)
+{
+#ifdef HDPVR_DEBUG
+ char print_buf[9];
+#endif
+ int ret, lines;
+
+ mutex_lock(&dev->usbc_mutex);
+ ret = usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ 0x81, 0x80 | 0x38,
+ 0x1800, 0x0003,
+ dev->usbc_buf, 3,
+ 1000);
+
+#ifdef HDPVR_DEBUG
+ if (hdpvr_debug & MSG_INFO) {
+ hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf,
+ sizeof(print_buf), 0);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "get input lines info returned: %d, %s\n", ret,
+ print_buf);
+ }
+#endif
+ lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
+ mutex_unlock(&dev->usbc_mutex);
+ return lines;
+}
+
+
+int hdpvr_set_bitrate(struct hdpvr_device *dev)
+{
+ int ret;
+
+ mutex_lock(&dev->usbc_mutex);
+ memset(dev->usbc_buf, 0, 4);
+ dev->usbc_buf[0] = dev->options.bitrate;
+ dev->usbc_buf[2] = dev->options.peak_bitrate;
+
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0x01, 0x38, CTRL_BITRATE_VALUE,
+ CTRL_DEFAULT_INDEX, dev->usbc_buf, 4, 1000);
+ mutex_unlock(&dev->usbc_mutex);
+
+ return ret;
+}
+
+int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
+ enum v4l2_mpeg_audio_encoding codec)
+{
+ int ret = 0;
+
+ if (dev->flags & HDPVR_FLAG_AC3_CAP) {
+ mutex_lock(&dev->usbc_mutex);
+ memset(dev->usbc_buf, 0, 2);
+ dev->usbc_buf[0] = input;
+ if (codec == V4L2_MPEG_AUDIO_ENCODING_AAC)
+ dev->usbc_buf[1] = 0;
+ else if (codec == V4L2_MPEG_AUDIO_ENCODING_AC3)
+ dev->usbc_buf[1] = 1;
+ else {
+ mutex_unlock(&dev->usbc_mutex);
+ v4l2_err(&dev->v4l2_dev, "invalid audio codec %d\n",
+ codec);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0x01, 0x38, CTRL_AUDIO_INPUT_VALUE,
+ CTRL_DEFAULT_INDEX, dev->usbc_buf, 2,
+ 1000);
+ mutex_unlock(&dev->usbc_mutex);
+ if (ret == 2)
+ ret = 0;
+ } else
+ ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE,
+ dev->options.audio_input+1);
+error:
+ return ret;
+}
+
+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_INPUT_VALUE,
+ dev->options.video_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,
+ dev->options.bitrate_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);
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/hdpvr/hdpvr-core.c b/linux/drivers/media/video/hdpvr/hdpvr-core.c
new file mode 100644
index 000000000..188bd5aea
--- /dev/null
+++ b/linux/drivers/media/video/hdpvr/hdpvr-core.c
@@ -0,0 +1,466 @@
+/*
+ * Hauppauge HD PVR USB driver
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2008 Janne Grunau (j@jannau.net)
+ * Copyright (C) 2008 John Poet
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+
+#include "hdpvr.h"
+
+static int video_nr[HDPVR_MAX] = {[0 ... (HDPVR_MAX - 1)] = UNSET};
+module_param_array(video_nr, int, NULL, 0);
+MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
+
+/* holds the number of currently registered devices */
+static atomic_t dev_nr = ATOMIC_INIT(-1);
+
+int hdpvr_debug;
+module_param(hdpvr_debug, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(hdpvr_debug, "enable debugging output");
+
+uint default_video_input = HDPVR_VIDEO_INPUTS;
+module_param(default_video_input, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / "
+ "1=S-Video / 2=Composite");
+
+uint default_audio_input = HDPVR_AUDIO_INPUTS;
+module_param(default_audio_input, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / "
+ "1=RCA front / 2=S/PDIF");
+
+static int boost_audio;
+module_param(boost_audio, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(boost_audio, "boost the audio signal");
+
+
+/* table of devices that work with this driver */
+static struct usb_device_id hdpvr_table[] = {
+ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) },
+ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) },
+ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, hdpvr_table);
+
+
+void hdpvr_delete(struct hdpvr_device *dev)
+{
+ hdpvr_free_buffers(dev);
+
+ if (dev->video_dev)
+ video_device_release(dev->video_dev);
+
+ usb_put_dev(dev->udev);
+}
+
+static void challenge(u8 *bytes)
+{
+ u64 *i64P, tmp64;
+ uint i, idx;
+
+ for (idx = 0; idx < 32; ++idx) {
+
+ if (idx & 0x3)
+ bytes[(idx >> 3) + 3] = bytes[(idx >> 2) & 0x3];
+
+ switch (idx & 0x3) {
+ case 0x3:
+ bytes[2] += bytes[3] * 4 + bytes[4] + bytes[5];
+ bytes[4] += bytes[(idx & 0x1) * 2] * 9 + 9;
+ break;
+ case 0x1:
+ bytes[0] *= 8;
+ bytes[0] += 7*idx + 4;
+ bytes[6] += bytes[3] * 3;
+ break;
+ case 0x0:
+ bytes[3 - (idx >> 3)] = bytes[idx >> 2];
+ bytes[5] += bytes[6] * 3;
+ for (i = 0; i < 3; i++)
+ bytes[3] *= bytes[3] + 1;
+ break;
+ case 0x2:
+ for (i = 0; i < 3; i++)
+ bytes[1] *= bytes[6] + 1;
+ for (i = 0; i < 3; i++) {
+ i64P = (u64 *)bytes;
+ tmp64 = le64_to_cpup(i64P);
+ tmp64 <<= bytes[7] & 0x0f;
+ *i64P += cpu_to_le64(tmp64);
+ }
+ break;
+ }
+ }
+}
+
+/* try to init the device like the windows driver */
+static int device_authorization(struct hdpvr_device *dev)
+{
+
+ int ret, retval = -ENOMEM;
+ char request_type = 0x38, rcv_request = 0x81;
+ char *response;
+#ifdef HDPVR_DEBUG
+ size_t buf_size = 46;
+ char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
+ if (!print_buf) {
+ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
+ goto error;
+ }
+#endif
+
+ mutex_lock(&dev->usbc_mutex);
+ ret = usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ rcv_request, 0x80 | request_type,
+ 0x0400, 0x0003,
+ dev->usbc_buf, 46,
+ 10000);
+ if (ret != 46) {
+ v4l2_err(&dev->v4l2_dev,
+ "unexpected answer of status request, len %d\n", ret);
+ goto error;
+ }
+#ifdef HDPVR_DEBUG
+ else {
+ hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
+ sizeof(print_buf), 0);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "Status request returned, len %d: %s\n",
+ ret, print_buf);
+ }
+#endif
+ if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION) {
+ dev->flags &= ~HDPVR_FLAG_AC3_CAP;
+ } else if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION_AC3) {
+ dev->flags |= HDPVR_FLAG_AC3_CAP;
+ } else if (dev->usbc_buf[1] > HDPVR_FIRMWARE_VERSION_AC3) {
+ v4l2_info(&dev->v4l2_dev, "untested firmware version 0x%x, "
+ "the driver might not work\n", dev->usbc_buf[1]);
+ dev->flags |= HDPVR_FLAG_AC3_CAP;
+ } else {
+ v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
+ dev->usbc_buf[1]);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ response = dev->usbc_buf+38;
+#ifdef HDPVR_DEBUG
+ hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n",
+ print_buf);
+#endif
+ challenge(response);
+#ifdef HDPVR_DEBUG
+ hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
+ print_buf);
+#endif
+
+ msleep(100);
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0xd1, 0x00 | request_type,
+ 0x0000, 0x0000,
+ response, 8,
+ 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:
+ return retval;
+}
+
+static int hdpvr_device_init(struct hdpvr_device *dev)
+{
+ int ret;
+ u8 *buf;
+ struct hdpvr_video_info *vidinf;
+
+ if (device_authorization(dev))
+ return -EACCES;
+
+ /* default options for init */
+ hdpvr_set_options(dev);
+
+ /* set filter options */
+ mutex_lock(&dev->usbc_mutex);
+ buf = dev->usbc_buf;
+ buf[0] = 0x03; buf[1] = 0x03; buf[2] = 0x00; buf[3] = 0x00;
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0x01, 0x38,
+ CTRL_LOW_PASS_FILTER_VALUE, CTRL_DEFAULT_INDEX,
+ buf, 4,
+ 1000);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "control request returned %d\n", ret);
+ mutex_unlock(&dev->usbc_mutex);
+
+ vidinf = get_video_info(dev);
+ if (!vidinf)
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "no valid video signal or device init failed\n");
+ else
+ kfree(vidinf);
+
+ /* enable fan and bling leds */
+ mutex_lock(&dev->usbc_mutex);
+ buf[0] = 0x1;
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0xd4, 0x38, 0, 0, buf, 1,
+ 1000);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "control request returned %d\n", ret);
+
+ /* boost analog audio */
+ buf[0] = boost_audio;
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0xd5, 0x38, 0, 0, buf, 1,
+ 1000);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "control request returned %d\n", ret);
+ mutex_unlock(&dev->usbc_mutex);
+
+ dev->status = STATUS_IDLE;
+ return 0;
+}
+
+static const struct hdpvr_options hdpvr_default_options = {
+ .video_std = HDPVR_60HZ,
+ .video_input = HDPVR_COMPONENT,
+ .audio_input = HDPVR_RCA_BACK,
+ .bitrate = 65, /* 6 mbps */
+ .peak_bitrate = 90, /* 9 mbps */
+ .bitrate_mode = HDPVR_CONSTANT,
+ .gop_mode = HDPVR_SIMPLE_IDR_GOP,
+ .audio_codec = V4L2_MPEG_AUDIO_ENCODING_AAC,
+ .brightness = 0x86,
+ .contrast = 0x80,
+ .hue = 0x80,
+ .saturation = 0x80,
+ .sharpness = 0x80,
+};
+
+static int hdpvr_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct hdpvr_device *dev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ size_t buffer_size;
+ int i;
+ int retval = -ENOMEM;
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ err("Out of memory");
+ goto error;
+ }
+
+ /* register v4l2_device early so it can be used for printks */
+ if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
+ err("v4l2_device_register failed");
+ goto error;
+ }
+
+ mutex_init(&dev->io_mutex);
+ mutex_init(&dev->i2c_mutex);
+ mutex_init(&dev->usbc_mutex);
+ dev->usbc_buf = kmalloc(64, GFP_KERNEL);
+ if (!dev->usbc_buf) {
+ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
+ goto error;
+ }
+
+ init_waitqueue_head(&dev->wait_buffer);
+ init_waitqueue_head(&dev->wait_data);
+
+ dev->workqueue = create_singlethread_workqueue("hdpvr_buffer");
+ if (!dev->workqueue)
+ goto error;
+
+ /* init video transfer queues */
+ INIT_LIST_HEAD(&dev->free_buff_list);
+ INIT_LIST_HEAD(&dev->rec_buff_list);
+
+ dev->options = hdpvr_default_options;
+
+ if (default_video_input < HDPVR_VIDEO_INPUTS)
+ dev->options.video_input = default_video_input;
+
+ if (default_audio_input < HDPVR_AUDIO_INPUTS)
+ dev->options.audio_input = default_audio_input;
+
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+
+ /* set up the endpoint information */
+ /* use only the first bulk-in and bulk-out endpoints */
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (!dev->bulk_in_endpointAddr &&
+ usb_endpoint_is_bulk_in(endpoint)) {
+ /* USB interface description is buggy, reported max
+ * packet size is 512 bytes, windows driver uses 8192 */
+ buffer_size = 8192;
+ dev->bulk_in_size = buffer_size;
+ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+ }
+
+ }
+ if (!dev->bulk_in_endpointAddr) {
+ v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
+ goto error;
+ }
+
+ /* init the device */
+ if (hdpvr_device_init(dev)) {
+ v4l2_err(&dev->v4l2_dev, "device init failed\n");
+ goto error;
+ }
+
+ mutex_lock(&dev->io_mutex);
+ if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
+ v4l2_err(&dev->v4l2_dev,
+ "allocating transfer buffers failed\n");
+ goto error;
+ }
+ mutex_unlock(&dev->io_mutex);
+
+ if (hdpvr_register_videodev(dev, &interface->dev,
+ video_nr[atomic_inc_return(&dev_nr)])) {
+ v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
+ goto error;
+ }
+
+#ifdef CONFIG_I2C
+ /* until i2c is working properly */
+ retval = 0; /* hdpvr_register_i2c_adapter(dev); */
+ if (retval < 0) {
+ v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
+ goto error;
+ }
+#endif /* CONFIG_I2C */
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ /* let the user know what node this device is now attached to */
+ v4l2_info(&dev->v4l2_dev, "device now attached to /dev/video%d\n",
+ dev->video_dev->minor);
+ return 0;
+
+error:
+ if (dev) {
+ mutex_unlock(&dev->io_mutex);
+ /* this frees allocated memory */
+ hdpvr_delete(dev);
+ }
+ return retval;
+}
+
+static void hdpvr_disconnect(struct usb_interface *interface)
+{
+ struct hdpvr_device *dev;
+ int minor;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ minor = dev->video_dev->minor;
+
+ /* prevent more I/O from starting and stop any ongoing */
+ mutex_lock(&dev->io_mutex);
+ dev->status = STATUS_DISCONNECTED;
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ video_unregister_device(dev->video_dev);
+ wake_up_interruptible(&dev->wait_data);
+ wake_up_interruptible(&dev->wait_buffer);
+ mutex_unlock(&dev->io_mutex);
+ msleep(100);
+ flush_workqueue(dev->workqueue);
+ mutex_lock(&dev->io_mutex);
+ hdpvr_cancel_queue(dev);
+ destroy_workqueue(dev->workqueue);
+ mutex_unlock(&dev->io_mutex);
+
+ /* deregister I2C adapter */
+#ifdef CONFIG_I2C
+ mutex_lock(&dev->i2c_mutex);
+ if (dev->i2c_adapter)
+ i2c_del_adapter(dev->i2c_adapter);
+ kfree(dev->i2c_adapter);
+ dev->i2c_adapter = NULL;
+ mutex_unlock(&dev->i2c_mutex);
+#endif /* CONFIG_I2C */
+
+ atomic_dec(&dev_nr);
+
+ v4l2_info(&dev->v4l2_dev, "device /dev/video%d disconnected\n", minor);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev->usbc_buf);
+ kfree(dev);
+}
+
+
+static struct usb_driver hdpvr_usb_driver = {
+ .name = "hdpvr",
+ .probe = hdpvr_probe,
+ .disconnect = hdpvr_disconnect,
+ .id_table = hdpvr_table,
+};
+
+static int __init hdpvr_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&hdpvr_usb_driver);
+ if (result)
+ err("usb_register failed. Error number %d", result);
+
+ return result;
+}
+
+static void __exit hdpvr_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&hdpvr_usb_driver);
+}
+
+module_init(hdpvr_init);
+module_exit(hdpvr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Janne Grunau");
+MODULE_DESCRIPTION("Hauppauge HD PVR driver");
diff --git a/linux/drivers/media/video/hdpvr/hdpvr-i2c.c b/linux/drivers/media/video/hdpvr/hdpvr-i2c.c
new file mode 100644
index 000000000..c4b5d1515
--- /dev/null
+++ b/linux/drivers/media/video/hdpvr/hdpvr-i2c.c
@@ -0,0 +1,145 @@
+
+/*
+ * Hauppauge HD PVR USB driver
+ *
+ * Copyright (C) 2008 Janne Grunau (j@jannau.net)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/i2c.h>
+
+#include "hdpvr.h"
+
+#define CTRL_READ_REQUEST 0xb8
+#define CTRL_WRITE_REQUEST 0x38
+
+#define REQTYPE_I2C_READ 0xb1
+#define REQTYPE_I2C_WRITE 0xb0
+#define REQTYPE_I2C_WRITE_STATT 0xd0
+
+static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
+ char *data, int len)
+{
+ int ret;
+ char *buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ REQTYPE_I2C_READ, CTRL_READ_REQUEST,
+ 0x100|addr, 0, buf, len, 1000);
+
+ if (ret == len) {
+ memcpy(data, buf, len);
+ ret = 0;
+ } else if (ret >= 0)
+ ret = -EIO;
+
+ kfree(buf);
+
+ return ret;
+}
+
+static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
+ char *data, int len)
+{
+ int ret;
+ char *buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, data, len);
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
+ 0x100|addr, 0, buf, len, 1000);
+
+ if (ret < 0)
+ goto error;
+
+ ret = usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
+ 0, 0, buf, 2, 1000);
+
+ if (ret == 2)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+error:
+ kfree(buf);
+ return ret;
+}
+
+static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
+ int num)
+{
+ struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
+ int retval = 0, i, addr;
+
+ if (num <= 0)
+ return 0;
+
+ mutex_lock(&dev->i2c_mutex);
+
+ for (i = 0; i < num && !retval; i++) {
+ addr = msgs[i].addr << 1;
+
+ if (msgs[i].flags & I2C_M_RD)
+ retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
+ msgs[i].len);
+ else
+ retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
+ msgs[i].len);
+ }
+
+ mutex_unlock(&dev->i2c_mutex);
+
+ return retval ? retval : num;
+}
+
+static u32 hdpvr_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm hdpvr_algo = {
+ .master_xfer = hdpvr_transfer,
+ .functionality = hdpvr_functionality,
+};
+
+int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
+{
+ struct i2c_adapter *i2c_adap;
+ int retval = -ENOMEM;
+
+ i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (i2c_adap == NULL)
+ goto error;
+
+ strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
+ 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;
+
+ i2c_set_adapdata(i2c_adap, dev);
+
+ retval = i2c_add_adapter(i2c_adap);
+
+ if (!retval)
+ dev->i2c_adapter = i2c_adap;
+ else
+ kfree(i2c_adap);
+
+error:
+ return retval;
+}
diff --git a/linux/drivers/media/video/hdpvr/hdpvr-video.c b/linux/drivers/media/video/hdpvr/hdpvr-video.c
new file mode 100644
index 000000000..3e6ffee8d
--- /dev/null
+++ b/linux/drivers/media/video/hdpvr/hdpvr-video.c
@@ -0,0 +1,1248 @@
+/*
+ * Hauppauge HD PVR USB driver - video 4 linux 2 interface
+ *
+ * Copyright (C) 2008 Janne Grunau (j@jannau.net)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include "hdpvr.h"
+
+#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
+
+#define print_buffer_status() { \
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \
+ "%s:%d buffer stat: %d free, %d proc\n", \
+ __func__, __LINE__, \
+ list_size(&dev->free_buff_list), \
+ list_size(&dev->rec_buff_list)); }
+
+struct hdpvr_fh {
+ struct hdpvr_device *dev;
+};
+
+static uint list_size(struct list_head *list)
+{
+ struct list_head *tmp;
+ uint count = 0;
+
+ list_for_each(tmp, list) {
+ count++;
+ }
+
+ return count;
+}
+
+/*=========================================================================*/
+/* urb callback */
+static void hdpvr_read_bulk_callback(struct urb *urb)
+{
+ struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
+ struct hdpvr_device *dev = buf->dev;
+
+ /* marking buffer as received and wake waiting */
+ buf->status = BUFSTAT_READY;
+ wake_up_interruptible(&dev->wait_data);
+}
+
+/*=========================================================================*/
+/* bufffer bits */
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_cancel_queue(struct hdpvr_device *dev)
+{
+ struct hdpvr_buffer *buf;
+
+ list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
+ usb_kill_urb(buf->urb);
+ buf->status = BUFSTAT_AVAILABLE;
+ }
+
+ list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
+
+ return 0;
+}
+
+static int hdpvr_free_queue(struct list_head *q)
+{
+ struct list_head *tmp;
+ struct list_head *p;
+ struct hdpvr_buffer *buf;
+ struct urb *urb;
+
+ for (p = q->next; p != q;) {
+ buf = list_entry(p, struct hdpvr_buffer, buff_list);
+
+ urb = buf->urb;
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ tmp = p->next;
+ list_del(p);
+ kfree(buf);
+ p = tmp;
+ }
+
+ return 0;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_free_buffers(struct hdpvr_device *dev)
+{
+ hdpvr_cancel_queue(dev);
+
+ hdpvr_free_queue(&dev->free_buff_list);
+ hdpvr_free_queue(&dev->rec_buff_list);
+
+ return 0;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
+{
+ uint i;
+ int retval = -ENOMEM;
+ u8 *mem;
+ struct hdpvr_buffer *buf;
+ struct urb *urb;
+
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "allocating %u buffers\n", count);
+
+ for (i = 0; i < count; i++) {
+
+ buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
+ if (!buf) {
+ v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n");
+ goto exit;
+ }
+ buf->dev = dev;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n");
+ goto exit;
+ }
+ buf->urb = urb;
+
+ mem = usb_buffer_alloc(dev->udev, dev->bulk_in_size, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!mem) {
+ v4l2_err(&dev->v4l2_dev,
+ "cannot allocate usb transfer buffer\n");
+ goto exit;
+ }
+
+ usb_fill_bulk_urb(buf->urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in_endpointAddr),
+ mem, dev->bulk_in_size,
+ hdpvr_read_bulk_callback, buf);
+
+ buf->status = BUFSTAT_AVAILABLE;
+ list_add_tail(&buf->buff_list, &dev->free_buff_list);
+ }
+ return 0;
+exit:
+ hdpvr_free_buffers(dev);
+ return retval;
+}
+
+static int hdpvr_submit_buffers(struct hdpvr_device *dev)
+{
+ struct hdpvr_buffer *buf;
+ struct urb *urb;
+ int ret = 0, err_count = 0;
+
+ mutex_lock(&dev->io_mutex);
+
+ while (dev->status == STATUS_STREAMING &&
+ !list_empty(&dev->free_buff_list)) {
+
+ buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
+ buff_list);
+ if (buf->status != BUFSTAT_AVAILABLE) {
+ v4l2_err(&dev->v4l2_dev,
+ "buffer not marked as availbale\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ urb = buf->urb;
+ urb->status = 0;
+ urb->actual_length = 0;
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "usb_submit_urb in %s returned %d\n",
+ __func__, ret);
+ if (++err_count > 2)
+ break;
+ continue;
+ }
+ buf->status = BUFSTAT_INPROGRESS;
+ list_move_tail(&buf->buff_list, &dev->rec_buff_list);
+ }
+err:
+ print_buffer_status();
+ mutex_unlock(&dev->io_mutex);
+ return ret;
+}
+
+static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev)
+{
+ struct hdpvr_buffer *buf;
+
+ mutex_lock(&dev->io_mutex);
+
+ if (list_empty(&dev->rec_buff_list)) {
+ mutex_unlock(&dev->io_mutex);
+ return NULL;
+ }
+
+ buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer,
+ buff_list);
+ mutex_unlock(&dev->io_mutex);
+
+ return buf;
+}
+
+static void hdpvr_transmit_buffers(struct work_struct *work)
+{
+ struct hdpvr_device *dev = container_of(work, struct hdpvr_device,
+ worker);
+
+ while (dev->status == STATUS_STREAMING) {
+
+ if (hdpvr_submit_buffers(dev)) {
+ v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n");
+ goto error;
+ }
+ if (wait_event_interruptible(dev->wait_buffer,
+ !list_empty(&dev->free_buff_list) ||
+ dev->status != STATUS_STREAMING))
+ goto error;
+ }
+
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "transmit worker exited\n");
+ return;
+error:
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "transmit buffers errored\n");
+ dev->status = STATUS_ERROR;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+static int hdpvr_start_streaming(struct hdpvr_device *dev)
+{
+ int ret;
+ struct hdpvr_video_info *vidinf;
+
+ if (dev->status == STATUS_STREAMING)
+ return 0;
+ else if (dev->status != STATUS_IDLE)
+ return -EAGAIN;
+
+ vidinf = get_video_info(dev);
+
+ if (vidinf) {
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "video signal: %dx%d@%dhz\n", vidinf->width,
+ vidinf->height, vidinf->fps);
+ kfree(vidinf);
+
+ /* start streaming 2 request */
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "encoder start control request returned %d\n", ret);
+
+ hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+
+ INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
+ queue_work(dev->workqueue, &dev->worker);
+
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "streaming started\n");
+ dev->status = STATUS_STREAMING;
+
+ return 0;
+ }
+ msleep(250);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "no video signal at input %d\n", dev->options.video_input);
+ return -EAGAIN;
+}
+
+
+/* function expects dev->io_mutex to be hold by caller */
+static int hdpvr_stop_streaming(struct hdpvr_device *dev)
+{
+ uint actual_length, c = 0;
+ u8 *buf;
+
+ if (dev->status == STATUS_IDLE)
+ return 0;
+ else if (dev->status != STATUS_STREAMING)
+ return -EAGAIN;
+
+ buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
+ if (!buf)
+ v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer "
+ "for emptying the internal device buffer. "
+ "Next capture start will be slow\n");
+
+ dev->status = STATUS_SHUTTING_DOWN;
+ hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
+ mutex_unlock(&dev->io_mutex);
+
+ wake_up_interruptible(&dev->wait_buffer);
+ msleep(50);
+
+ flush_workqueue(dev->workqueue);
+
+ mutex_lock(&dev->io_mutex);
+ /* kill the still outstanding urbs */
+ hdpvr_cancel_queue(dev);
+
+ /* emptying the device buffer beforeshutting it down */
+ while (buf && ++c < 500 &&
+ !usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in_endpointAddr),
+ buf, dev->bulk_in_size, &actual_length,
+ BULK_URB_TIMEOUT)) {
+ /* wait */
+ msleep(5);
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "%2d: got %d bytes\n", c, actual_length);
+ }
+ kfree(buf);
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "used %d urbs to empty device buffers\n", c-1);
+ msleep(10);
+
+ dev->status = STATUS_IDLE;
+
+ return 0;
+}
+
+
+/*=======================================================================*/
+/*
+ * video 4 linux 2 file operations
+ */
+
+static int hdpvr_open(struct file *file)
+{
+ struct hdpvr_device *dev;
+ struct hdpvr_fh *fh;
+ int retval = -ENOMEM;
+
+ dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
+ if (!dev) {
+ v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n");
+ retval = -ENODEV;
+ goto err;
+ }
+
+ fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
+ if (!fh) {
+ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
+ goto err;
+ }
+ /* lock the device to allow correctly handling errors
+ * in resumption */
+ mutex_lock(&dev->io_mutex);
+ dev->open_count++;
+
+ fh->dev = dev;
+
+ /* save our object in the file's private structure */
+ file->private_data = fh;
+
+ retval = 0;
+err:
+ mutex_unlock(&dev->io_mutex);
+ return retval;
+}
+
+static int hdpvr_release(struct file *file)
+{
+ struct hdpvr_fh *fh = (struct hdpvr_fh *)file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->io_mutex);
+ if (!(--dev->open_count) && dev->status == STATUS_STREAMING)
+ hdpvr_stop_streaming(dev);
+
+ mutex_unlock(&dev->io_mutex);
+
+ return 0;
+}
+
+/*
+ * hdpvr_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
+ loff_t *pos)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_buffer *buf = NULL;
+ struct urb *urb;
+ unsigned int ret = 0;
+ int rem, cnt;
+
+ if (*pos)
+ return -ESPIPE;
+
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->io_mutex);
+ if (dev->status == STATUS_IDLE) {
+ if (hdpvr_start_streaming(dev)) {
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "start_streaming failed\n");
+ ret = -EIO;
+ msleep(200);
+ dev->status = STATUS_IDLE;
+ mutex_unlock(&dev->io_mutex);
+ goto err;
+ }
+ print_buffer_status();
+ }
+ mutex_unlock(&dev->io_mutex);
+
+ /* wait for the first buffer */
+ if (!(file->f_flags & O_NONBLOCK)) {
+ if (wait_event_interruptible(dev->wait_data,
+ hdpvr_get_next_buffer(dev)))
+ return -ERESTARTSYS;
+ }
+
+ buf = hdpvr_get_next_buffer(dev);
+
+ while (count > 0 && buf) {
+
+ if (buf->status != BUFSTAT_READY &&
+ dev->status != STATUS_DISCONNECTED) {
+ /* return nonblocking */
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ if (wait_event_interruptible(dev->wait_data,
+ buf->status == BUFSTAT_READY)) {
+ ret = -ERESTARTSYS;
+ goto err;
+ }
+ }
+
+ if (buf->status != BUFSTAT_READY)
+ break;
+
+ /* set remaining bytes to copy */
+ urb = buf->urb;
+ rem = urb->actual_length - buf->pos;
+ cnt = rem > count ? count : rem;
+
+ if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
+ cnt)) {
+ v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
+ if (!ret)
+ ret = -EFAULT;
+ goto err;
+ }
+
+ buf->pos += cnt;
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+
+ /* finished, take next buffer */
+ if (buf->pos == urb->actual_length) {
+ mutex_lock(&dev->io_mutex);
+ buf->pos = 0;
+ buf->status = BUFSTAT_AVAILABLE;
+
+ list_move_tail(&buf->buff_list, &dev->free_buff_list);
+
+ print_buffer_status();
+
+ mutex_unlock(&dev->io_mutex);
+
+ wake_up_interruptible(&dev->wait_buffer);
+
+ buf = hdpvr_get_next_buffer(dev);
+ }
+ }
+err:
+ if (!ret && !buf)
+ ret = -EAGAIN;
+ return ret;
+}
+
+static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
+{
+ struct hdpvr_buffer *buf = NULL;
+ struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ unsigned int mask = 0;
+
+ mutex_lock(&dev->io_mutex);
+
+ if (video_is_unregistered(dev->video_dev))
+ return -EIO;
+
+ if (dev->status == STATUS_IDLE) {
+ if (hdpvr_start_streaming(dev)) {
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "start_streaming failed\n");
+ dev->status = STATUS_IDLE;
+ }
+
+ print_buffer_status();
+ }
+ mutex_unlock(&dev->io_mutex);
+
+ buf = hdpvr_get_next_buffer(dev);
+ /* only wait if no data is available */
+ if (!buf || buf->status != BUFSTAT_READY) {
+ poll_wait(filp, &dev->wait_data, wait);
+ buf = hdpvr_get_next_buffer(dev);
+ }
+ if (buf && buf->status == BUFSTAT_READY)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+
+static const struct v4l2_file_operations hdpvr_fops = {
+ .owner = THIS_MODULE,
+ .open = hdpvr_open,
+ .release = hdpvr_release,
+ .read = hdpvr_read,
+ .poll = hdpvr_poll,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+/*=======================================================================*/
+/*
+ * V4L2 ioctl handling
+ */
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+
+ strcpy(cap->driver, "hdpvr");
+ strcpy(cap->card, "Haupauge HD PVR");
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->version = HDPVR_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *private_data,
+ v4l2_std_id *std)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ u8 std_type = 1;
+
+ if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
+ std_type = 0;
+
+ return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
+}
+
+static const char *iname[] = {
+ [HDPVR_COMPONENT] = "Component",
+ [HDPVR_SVIDEO] = "S-Video",
+ [HDPVR_COMPOSITE] = "Composite",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ unsigned int n;
+
+ n = i->index;
+ if (n >= HDPVR_VIDEO_INPUTS)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(i->name, iname[n], sizeof(i->name) - 1);
+ i->name[sizeof(i->name) - 1] = '\0';
+
+ i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
+
+ i->std = dev->video_dev->tvnorms;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *private_data,
+ unsigned int index)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int retval;
+
+ if (index >= HDPVR_VIDEO_INPUTS)
+ return -EINVAL;
+
+ if (dev->status != STATUS_IDLE)
+ return -EAGAIN;
+
+ retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
+ if (!retval)
+ dev->options.video_input = index;
+
+ return retval;
+}
+
+static int vidioc_g_input(struct file *file, void *private_data,
+ unsigned int *index)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+
+ *index = dev->options.video_input;
+ return 0;
+}
+
+
+static const char *audio_iname[] = {
+ [HDPVR_RCA_FRONT] = "RCA front",
+ [HDPVR_RCA_BACK] = "RCA back",
+ [HDPVR_SPDIF] = "SPDIF",
+};
+
+static int vidioc_enumaudio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ unsigned int n;
+
+ n = audio->index;
+ if (n >= HDPVR_AUDIO_INPUTS)
+ return -EINVAL;
+
+ audio->capability = V4L2_AUDCAP_STEREO;
+
+ strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1);
+ audio->name[sizeof(audio->name) - 1] = '\0';
+
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *private_data,
+ struct v4l2_audio *audio)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int retval;
+
+ if (audio->index >= HDPVR_AUDIO_INPUTS)
+ return -EINVAL;
+
+ if (dev->status != STATUS_IDLE)
+ return -EAGAIN;
+
+ retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
+ if (!retval)
+ dev->options.audio_input = audio->index;
+
+ return retval;
+}
+
+static int vidioc_g_audio(struct file *file, void *private_data,
+ struct v4l2_audio *audio)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+
+ audio->index = dev->options.audio_input;
+ audio->capability = V4L2_AUDCAP_STEREO;
+ strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
+ audio->name[sizeof(audio->name) - 1] = '\0';
+ return 0;
+}
+
+static const s32 supported_v4l2_ctrls[] = {
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_SHARPNESS,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+};
+
+static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
+ int ac3)
+{
+ int err;
+
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_SHARPNESS:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(
+ qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
+ ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
+ : V4L2_MPEG_AUDIO_ENCODING_AAC,
+ 1, V4L2_MPEG_AUDIO_ENCODING_AAC);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return v4l2_ctrl_query_fill(
+ qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+
+/* case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
+/* return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return v4l2_ctrl_query_fill(
+ qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
+ 6500000);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
+ 9000000);
+ if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
+ qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vidioc_queryctrl(struct file *file, void *private_data,
+ struct v4l2_queryctrl *qc)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int i, next;
+ u32 id = qc->id;
+
+ memset(qc, 0, sizeof(*qc));
+
+ next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
+ qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+ for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
+ if (next) {
+ if (qc->id < supported_v4l2_ctrls[i])
+ qc->id = supported_v4l2_ctrls[i];
+ else
+ continue;
+ }
+
+ if (qc->id == supported_v4l2_ctrls[i])
+ return fill_queryctrl(&dev->options, qc,
+ dev->flags & HDPVR_FLAG_AC3_CAP);
+
+ if (qc->id < supported_v4l2_ctrls[i])
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *private_data,
+ struct v4l2_control *ctrl)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = dev->options.brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = dev->options.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = dev->options.saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = dev->options.hue;
+ break;
+ case V4L2_CID_SHARPNESS:
+ ctrl->value = dev->options.sharpness;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *private_data,
+ struct v4l2_control *ctrl)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int retval;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
+ if (!retval)
+ dev->options.brightness = ctrl->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
+ if (!retval)
+ dev->options.contrast = ctrl->value;
+ break;
+ case V4L2_CID_SATURATION:
+ retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
+ if (!retval)
+ dev->options.saturation = ctrl->value;
+ break;
+ case V4L2_CID_HUE:
+ retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
+ if (!retval)
+ dev->options.hue = ctrl->value;
+ break;
+ case V4L2_CID_SHARPNESS:
+ retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
+ if (!retval)
+ dev->options.sharpness = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return retval;
+}
+
+
+static int hdpvr_get_ctrl(struct hdpvr_options *opt,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ ctrl->value = opt->audio_codec;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
+ break;
+/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/* ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
+/* break; */
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
+ ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
+ : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctrl->value = opt->bitrate * 100000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ ctrl->value = opt->peak_bitrate * 100000;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = hdpvr_get_ctrl(&dev->options, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+
+ }
+
+ return -EINVAL;
+}
+
+
+static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+ int ret = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
+ (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
+ ret = 0;
+ break;
+/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/* if (ctrl->value == 0 || ctrl->value == 128) */
+/* ret = 0; */
+/* break; */
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
+ ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ {
+ uint bitrate = ctrl->value / 100000;
+ if (bitrate >= 10 && bitrate <= 135)
+ ret = 0;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ {
+ uint peak_bitrate = ctrl->value / 100000;
+ if (peak_bitrate >= 10 && peak_bitrate <= 202)
+ ret = 0;
+ break;
+ }
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
+ ret = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = hdpvr_try_ctrl(ctrl,
+ dev->flags & HDPVR_FLAG_AC3_CAP);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+
+ return -EINVAL;
+}
+
+
+static int hdpvr_set_ctrl(struct hdpvr_device *dev,
+ struct v4l2_ext_control *ctrl)
+{
+ struct hdpvr_options *opt = &dev->options;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ if (dev->flags & HDPVR_FLAG_AC3_CAP) {
+ opt->audio_codec = ctrl->value;
+ ret = hdpvr_set_audio(dev, opt->audio_input,
+ opt->audio_codec);
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ break;
+/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
+/* opt->gop_mode |= 0x2; */
+/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
+/* opt->gop_mode); */
+/* } */
+/* if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
+/* opt->gop_mode &= ~0x2; */
+/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
+/* opt->gop_mode); */
+/* } */
+/* break; */
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
+ opt->bitrate_mode != HDPVR_CONSTANT) {
+ opt->bitrate_mode = HDPVR_CONSTANT;
+ hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+ opt->bitrate_mode);
+ }
+ if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ opt->bitrate_mode == HDPVR_CONSTANT) {
+ opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
+ hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+ opt->bitrate_mode);
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE: {
+ uint bitrate = ctrl->value / 100000;
+
+ opt->bitrate = bitrate;
+ if (bitrate >= opt->peak_bitrate)
+ opt->peak_bitrate = bitrate+1;
+
+ hdpvr_set_bitrate(dev);
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
+ uint peak_bitrate = ctrl->value / 100000;
+
+ if (opt->bitrate_mode == HDPVR_CONSTANT)
+ break;
+
+ if (opt->bitrate < peak_bitrate) {
+ opt->peak_bitrate = peak_bitrate;
+ hdpvr_set_bitrate(dev);
+ } else
+ ret = -EINVAL;
+ break;
+ }
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = hdpvr_try_ctrl(ctrl,
+ dev->flags & HDPVR_FLAG_AC3_CAP);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ err = hdpvr_set_ctrl(dev, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
+ struct v4l2_fmtdesc *f)
+{
+
+ if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32);
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
+ struct v4l2_format *f)
+{
+ struct hdpvr_fh *fh = file->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_video_info *vid_info;
+
+ if (!dev)
+ return -ENODEV;
+
+ vid_info = get_video_info(dev);
+ if (!vid_info)
+ return -EFAULT;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.width = vid_info->width;
+ f->fmt.pix.height = vid_info->height;
+ f->fmt.pix.sizeimage = dev->bulk_in_size;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.field = V4L2_FIELD_ANY;
+
+ kfree(vid_info);
+ return 0;
+}
+
+static int vidioc_encoder_cmd(struct file *filp, void *priv,
+ struct v4l2_encoder_cmd *a)
+{
+ struct hdpvr_fh *fh = filp->private_data;
+ struct hdpvr_device *dev = fh->dev;
+ int res;
+
+ mutex_lock(&dev->io_mutex);
+
+ memset(&a->raw, 0, sizeof(a->raw));
+ switch (a->cmd) {
+ case V4L2_ENC_CMD_START:
+ a->flags = 0;
+ res = hdpvr_start_streaming(dev);
+ break;
+ case V4L2_ENC_CMD_STOP:
+ res = hdpvr_stop_streaming(dev);
+ break;
+ default:
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "Unsupported encoder cmd %d\n", a->cmd);
+ res = -EINVAL;
+ }
+ mutex_unlock(&dev->io_mutex);
+ return res;
+}
+
+static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
+ struct v4l2_encoder_cmd *a)
+{
+ switch (a->cmd) {
+ case V4L2_ENC_CMD_START:
+ case V4L2_ENC_CMD_STOP:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_enumaudio = vidioc_enumaudio,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_encoder_cmd = vidioc_encoder_cmd,
+ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
+};
+
+static void hdpvr_device_release(struct video_device *vdev)
+{
+ struct hdpvr_device *dev = video_get_drvdata(vdev);
+
+ hdpvr_delete(dev);
+}
+
+static const struct video_device hdpvr_video_template = {
+/* .type = VFL_TYPE_GRABBER, */
+/* .type2 = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */
+ .fops = &hdpvr_fops,
+ .release = hdpvr_device_release,
+ .ioctl_ops = &hdpvr_ioctl_ops,
+ .tvnorms =
+ V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_B |
+ V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
+ V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
+ V4L2_STD_PAL_60,
+};
+
+int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
+ int devnum)
+{
+ /* setup and register video device */
+ dev->video_dev = video_device_alloc();
+ if (!dev->video_dev) {
+ v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
+ goto error;
+ }
+
+ *(dev->video_dev) = hdpvr_video_template;
+ strcpy(dev->video_dev->name, "Hauppauge HD PVR");
+ dev->video_dev->parent = parent;
+ video_set_drvdata(dev->video_dev, dev);
+
+ if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
+ v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
+ goto error;
+ }
+
+ return 0;
+error:
+ return -ENOMEM;
+}
diff --git a/linux/drivers/media/video/hdpvr/hdpvr.h b/linux/drivers/media/video/hdpvr/hdpvr.h
new file mode 100644
index 000000000..1edd87591
--- /dev/null
+++ b/linux/drivers/media/video/hdpvr/hdpvr.h
@@ -0,0 +1,303 @@
+/*
+ * Hauppauge HD PVR USB driver
+ *
+ * Copyright (C) 2008 Janne Grunau (j@jannau.net)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+
+#define HDPVR_MAJOR_VERSION 0
+#define HDPVR_MINOR_VERSION 2
+#define HDPVR_RELEASE 0
+#define HDPVR_VERSION \
+ KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
+
+#define HDPVR_MAX 8
+
+/* Define these values to match your devices */
+#define HD_PVR_VENDOR_ID 0x2040
+#define HD_PVR_PRODUCT_ID 0x4900
+#define HD_PVR_PRODUCT_ID1 0x4901
+#define HD_PVR_PRODUCT_ID2 0x4902
+
+#define UNSET (-1U)
+
+#define NUM_BUFFERS 64
+
+#define HDPVR_FIRMWARE_VERSION 0x8
+#define HDPVR_FIRMWARE_VERSION_AC3 0xd
+
+/* #define HDPVR_DEBUG */
+
+extern int hdpvr_debug;
+
+#define MSG_INFO 1
+#define MSG_BUFFER 2
+
+struct hdpvr_options {
+ u8 video_std;
+ u8 video_input;
+ u8 audio_input;
+ u8 bitrate; /* in 100kbps */
+ u8 peak_bitrate; /* in 100kbps */
+ u8 bitrate_mode;
+ u8 gop_mode;
+ enum v4l2_mpeg_audio_encoding audio_codec;
+ u8 brightness;
+ u8 contrast;
+ u8 hue;
+ u8 saturation;
+ u8 sharpness;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct hdpvr_device {
+ /* the v4l device for this device */
+ struct video_device *video_dev;
+ /* the usb device for this device */
+ struct usb_device *udev;
+ /* v4l2-device unused */
+ struct v4l2_device v4l2_dev;
+
+ /* the max packet size of the bulk endpoint */
+ size_t bulk_in_size;
+ /* the address of the bulk in endpoint */
+ __u8 bulk_in_endpointAddr;
+
+ /* holds the current device status */
+ __u8 status;
+ /* count the number of openers */
+ uint open_count;
+
+ /* holds the cureent set options */
+ struct hdpvr_options options;
+
+ uint flags;
+
+ /* synchronize I/O */
+ struct mutex io_mutex;
+ /* available buffers */
+ struct list_head free_buff_list;
+ /* in progress buffers */
+ struct list_head rec_buff_list;
+ /* waitqueue for buffers */
+ wait_queue_head_t wait_buffer;
+ /* waitqueue for data */
+ wait_queue_head_t wait_data;
+ /**/
+ struct workqueue_struct *workqueue;
+ /**/
+ struct work_struct worker;
+
+ /* I2C adapter */
+ struct i2c_adapter *i2c_adapter;
+ /* I2C lock */
+ struct mutex i2c_mutex;
+
+ /* usb control transfer buffer and lock */
+ struct mutex usbc_mutex;
+ u8 *usbc_buf;
+};
+
+
+/* buffer one bulk urb of data */
+struct hdpvr_buffer {
+ struct list_head buff_list;
+
+ struct urb *urb;
+
+ struct hdpvr_device *dev;
+
+ uint pos;
+
+ __u8 status;
+};
+
+/* */
+
+struct hdpvr_video_info {
+ u16 width;
+ u16 height;
+ u8 fps;
+};
+
+enum {
+ STATUS_UNINITIALIZED = 0,
+ STATUS_IDLE,
+ STATUS_STARTING,
+ STATUS_SHUTTING_DOWN,
+ STATUS_STREAMING,
+ STATUS_ERROR,
+ STATUS_DISCONNECTED,
+};
+
+enum {
+ HDPVR_FLAG_AC3_CAP = 1,
+};
+
+enum {
+ BUFSTAT_UNINITIALIZED = 0,
+ BUFSTAT_AVAILABLE,
+ BUFSTAT_INPROGRESS,
+ BUFSTAT_READY,
+};
+
+#define CTRL_START_STREAMING_VALUE 0x0700
+#define CTRL_STOP_STREAMING_VALUE 0x0800
+#define CTRL_BITRATE_VALUE 0x1000
+#define CTRL_BITRATE_MODE_VALUE 0x1200
+#define CTRL_GOP_MODE_VALUE 0x1300
+#define CTRL_VIDEO_INPUT_VALUE 0x1500
+#define CTRL_VIDEO_STD_TYPE 0x1700
+#define CTRL_AUDIO_INPUT_VALUE 0x2500
+#define CTRL_BRIGHTNESS 0x2900
+#define CTRL_CONTRAST 0x2a00
+#define CTRL_HUE 0x2b00
+#define CTRL_SATURATION 0x2c00
+#define CTRL_SHARPNESS 0x2d00
+#define CTRL_LOW_PASS_FILTER_VALUE 0x3100
+
+#define CTRL_DEFAULT_INDEX 0x0003
+
+
+ /* :0 s 38 01 1000 0003 0004 4 = 0a00ca00
+ * BITRATE SETTING
+ * 1st and 2nd byte (little endian): average bitrate in 100 000 bit/s
+ * min: 1 mbit/s, max: 13.5 mbit/s
+ * 3rd and 4th byte (little endian): peak bitrate in 100 000 bit/s
+ * min: average + 100kbit/s,
+ * max: 20.2 mbit/s
+ */
+
+ /* :0 s 38 01 1200 0003 0001 1 = 02
+ * BIT RATE MODE
+ * constant = 1, variable (peak) = 2, variable (average) = 3
+ */
+
+ /* :0 s 38 01 1300 0003 0001 1 = 03
+ * GOP MODE (2 bit)
+ * low bit 0/1: advanced/simple GOP
+ * high bit 0/1: IDR(4/32/128) / no IDR (4/32/0)
+ */
+
+ /* :0 s 38 01 1700 0003 0001 1 = 00
+ * VIDEO STANDARD or FREQUNCY 0 = 60hz, 1 = 50hz
+ */
+
+ /* :0 s 38 01 3100 0003 0004 4 = 03030000
+ * FILTER CONTROL
+ * 1st byte luma low pass filter strength,
+ * 2nd byte chroma low pass filter strength,
+ * 3rd byte MF enable chroma, min=0, max=1
+ * 4th byte n
+ */
+
+
+ /* :0 s 38 b9 0001 0000 0000 0 */
+
+
+
+/* :0 s 38 d3 0000 0000 0001 1 = 00 */
+/* ret = usb_control_msg(dev->udev, */
+/* usb_sndctrlpipe(dev->udev, 0), */
+/* 0xd3, 0x38, */
+/* 0, 0, */
+/* "\0", 1, */
+/* 1000); */
+
+/* info("control request returned %d", ret); */
+/* msleep(5000); */
+
+
+ /* :0 s b8 81 1400 0003 0005 5 <
+ * :0 0 5 = d0024002 19
+ * QUERY FRAME SIZE AND RATE
+ * 1st and 2nd byte (little endian): horizontal resolution
+ * 3rd and 4th byte (little endian): vertical resolution
+ * 5th byte: frame rate
+ */
+
+ /* :0 s b8 81 1800 0003 0003 3 <
+ * :0 0 3 = 030104
+ * QUERY SIGNAL AND DETECTED LINES, maybe INPUT
+ */
+
+enum hdpvr_video_std {
+ HDPVR_60HZ = 0,
+ HDPVR_50HZ,
+};
+
+enum hdpvr_video_input {
+ HDPVR_COMPONENT = 0,
+ HDPVR_SVIDEO,
+ HDPVR_COMPOSITE,
+ HDPVR_VIDEO_INPUTS
+};
+
+enum hdpvr_audio_inputs {
+ HDPVR_RCA_BACK = 0,
+ HDPVR_RCA_FRONT,
+ HDPVR_SPDIF,
+ HDPVR_AUDIO_INPUTS
+};
+
+enum hdpvr_bitrate_mode {
+ HDPVR_CONSTANT = 1,
+ HDPVR_VARIABLE_PEAK,
+ HDPVR_VARIABLE_AVERAGE,
+};
+
+enum hdpvr_gop_mode {
+ HDPVR_ADVANCED_IDR_GOP = 0,
+ HDPVR_SIMPLE_IDR_GOP,
+ HDPVR_ADVANCED_NOIDR_GOP,
+ HDPVR_SIMPLE_NOIDR_GOP,
+};
+
+void hdpvr_delete(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* hardware control functions */
+int hdpvr_set_options(struct hdpvr_device *dev);
+
+int hdpvr_set_bitrate(struct hdpvr_device *dev);
+
+int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
+ enum v4l2_mpeg_audio_encoding codec);
+
+int hdpvr_config_call(struct hdpvr_device *dev, uint value,
+ unsigned char valbuf);
+
+struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev);
+
+/* :0 s b8 81 1800 0003 0003 3 < */
+/* :0 0 3 = 0301ff */
+int get_input_lines_info(struct hdpvr_device *dev);
+
+
+/*========================================================================*/
+/* v4l2 registration */
+int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
+ int devnumber);
+
+int hdpvr_cancel_queue(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* i2c adapter registration */
+int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* buffer management */
+int hdpvr_free_buffers(struct hdpvr_device *dev);
+int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count);
diff --git a/linux/drivers/media/video/indycam.c b/linux/drivers/media/video/indycam.c
index 84b9e4f2b..f2da0550b 100644
--- a/linux/drivers/media/video/indycam.c
+++ b/linux/drivers/media/video/indycam.c
@@ -19,10 +19,12 @@
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/videodev.h>
/* IndyCam decodes stream of photons into digital image representation ;-) */
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
#include "indycam.h"
@@ -33,6 +35,12 @@ MODULE_VERSION(INDYCAM_MODULE_VERSION);
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = { 0x56 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+#endif
+
// #define INDYCAM_DEBUG
#ifdef INDYCAM_DEBUG
@@ -44,11 +52,14 @@ MODULE_LICENSE("GPL");
#endif
struct indycam {
- struct i2c_client *client;
+ struct v4l2_subdev sd;
u8 version;
};
-static struct i2c_driver i2c_driver_indycam;
+static inline struct indycam *to_indycam(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct indycam, sd);
+}
static const u8 initseq[] = {
INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
@@ -63,8 +74,9 @@ static const u8 initseq[] = {
/* IndyCam register handling */
-static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
+static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
if (reg == INDYCAM_REG_RESET) {
@@ -87,12 +99,12 @@ static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
return 0;
}
-static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
+static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int err;
- if ((reg == INDYCAM_REG_BRIGHTNESS)
- || (reg == INDYCAM_REG_VERSION)) {
+ if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) {
dprintk("indycam_write_reg(): "
"skipping read-only register %d\n", reg);
return 0;
@@ -108,13 +120,13 @@ static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
return err;
}
-static int indycam_write_block(struct i2c_client *client, u8 reg,
+static int indycam_write_block(struct v4l2_subdev *sd, u8 reg,
u8 length, u8 *data)
{
int i, err;
for (i = 0; i < length; i++) {
- err = indycam_write_reg(client, reg + i, data[i]);
+ err = indycam_write_reg(sd, reg + i, data[i]);
if (err)
return err;
}
@@ -125,79 +137,78 @@ static int indycam_write_block(struct i2c_client *client, u8 reg,
/* Helper functions */
#ifdef INDYCAM_DEBUG
-static void indycam_regdump_debug(struct i2c_client *client)
+static void indycam_regdump_debug(struct v4l2_subdev *sd)
{
int i;
u8 val;
for (i = 0; i < 9; i++) {
- indycam_read_reg(client, i, &val);
+ indycam_read_reg(sd, i, &val);
dprintk("Reg %d = 0x%02x\n", i, val);
}
}
#endif
-static int indycam_get_control(struct i2c_client *client,
- struct indycam_control *ctrl)
+static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct indycam *camera = i2c_get_clientdata(client);
+ struct indycam *camera = to_indycam(sd);
u8 reg;
int ret = 0;
- switch (ctrl->type) {
- case INDYCAM_CONTROL_AGC:
- case INDYCAM_CONTROL_AWB:
- ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
if (ret)
return -EIO;
- if (ctrl->type == INDYCAM_CONTROL_AGC)
+ if (ctrl->id == V4L2_CID_AUTOGAIN)
ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
? 1 : 0;
else
ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
? 1 : 0;
break;
- case INDYCAM_CONTROL_SHUTTER:
- ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, &reg);
+ case V4L2_CID_EXPOSURE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, &reg);
if (ret)
return -EIO;
ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
break;
- case INDYCAM_CONTROL_GAIN:
- ret = indycam_read_reg(client, INDYCAM_REG_GAIN, &reg);
+ case V4L2_CID_GAIN:
+ ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
- case INDYCAM_CONTROL_RED_BALANCE:
- ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, &reg);
+ case V4L2_CID_RED_BALANCE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
- case INDYCAM_CONTROL_BLUE_BALANCE:
- ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, &reg);
+ case V4L2_CID_BLUE_BALANCE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
case INDYCAM_CONTROL_RED_SATURATION:
- ret = indycam_read_reg(client,
+ ret = indycam_read_reg(sd,
INDYCAM_REG_RED_SATURATION, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
case INDYCAM_CONTROL_BLUE_SATURATION:
- ret = indycam_read_reg(client,
+ ret = indycam_read_reg(sd,
INDYCAM_REG_BLUE_SATURATION, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
- case INDYCAM_CONTROL_GAMMA:
+ case V4L2_CID_GAMMA:
if (camera->version == CAMERA_VERSION_MOOSE) {
- ret = indycam_read_reg(client,
+ ret = indycam_read_reg(sd,
INDYCAM_REG_GAMMA, &reg);
if (ret)
return -EIO;
@@ -213,21 +224,20 @@ static int indycam_get_control(struct i2c_client *client,
return ret;
}
-static int indycam_set_control(struct i2c_client *client,
- struct indycam_control *ctrl)
+static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct indycam *camera = i2c_get_clientdata(client);
+ struct indycam *camera = to_indycam(sd);
u8 reg;
int ret = 0;
- switch (ctrl->type) {
- case INDYCAM_CONTROL_AGC:
- case INDYCAM_CONTROL_AWB:
- ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
if (ret)
break;
- if (ctrl->type == INDYCAM_CONTROL_AGC) {
+ if (ctrl->id == V4L2_CID_AUTOGAIN) {
if (ctrl->value)
reg |= INDYCAM_CONTROL_AGCENA;
else
@@ -239,34 +249,34 @@ static int indycam_set_control(struct i2c_client *client,
reg &= ~INDYCAM_CONTROL_AWBCTL;
}
- ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg);
+ ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg);
break;
- case INDYCAM_CONTROL_SHUTTER:
+ case V4L2_CID_EXPOSURE:
reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
- ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg);
+ ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg);
break;
- case INDYCAM_CONTROL_GAIN:
- ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value);
+ case V4L2_CID_GAIN:
+ ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value);
break;
- case INDYCAM_CONTROL_RED_BALANCE:
- ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE,
+ case V4L2_CID_RED_BALANCE:
+ ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE,
ctrl->value);
break;
- case INDYCAM_CONTROL_BLUE_BALANCE:
- ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE,
+ case V4L2_CID_BLUE_BALANCE:
+ ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE,
ctrl->value);
break;
case INDYCAM_CONTROL_RED_SATURATION:
- ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION,
+ ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION,
ctrl->value);
break;
case INDYCAM_CONTROL_BLUE_SATURATION:
- ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION,
+ ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION,
ctrl->value);
break;
- case INDYCAM_CONTROL_GAMMA:
+ case V4L2_CID_GAMMA:
if (camera->version == CAMERA_VERSION_MOOSE) {
- ret = indycam_write_reg(client, INDYCAM_REG_GAMMA,
+ ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA,
ctrl->value);
}
break;
@@ -279,192 +289,107 @@ static int indycam_set_control(struct i2c_client *client,
/* I2C-interface */
-static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
+static int indycam_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct indycam *camera = to_indycam(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
+ camera->version);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops indycam_core_ops = {
+ .g_chip_ident = indycam_g_chip_ident,
+ .g_ctrl = indycam_g_ctrl,
+ .s_ctrl = indycam_s_ctrl,
+};
+
+static const struct v4l2_subdev_ops indycam_ops = {
+ .core = &indycam_core_ops,
+};
+
+static int indycam_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err = 0;
struct indycam *camera;
- struct i2c_client *client;
+ struct v4l2_subdev *sd;
- printk(KERN_INFO "SGI IndyCam driver version %s\n",
- INDYCAM_MODULE_VERSION);
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
- if (!camera) {
- err = -ENOMEM;
- goto out_free_client;
- }
-
- client->addr = addr;
- client->adapter = adap;
- client->driver = &i2c_driver_indycam;
- client->flags = 0;
- strcpy(client->name, "IndyCam client");
- i2c_set_clientdata(client, camera);
-
- camera->client = client;
+ if (!camera)
+ return -ENOMEM;
- err = i2c_attach_client(client);
- if (err)
- goto out_free_camera;
+ sd = &camera->sd;
+ v4l2_i2c_subdev_init(sd, client, &indycam_ops);
camera->version = i2c_smbus_read_byte_data(client,
INDYCAM_REG_VERSION);
if (camera->version != CAMERA_VERSION_INDY &&
camera->version != CAMERA_VERSION_MOOSE) {
- err = -ENODEV;
- goto out_detach_client;
+ kfree(camera);
+ return -ENODEV;
}
+
printk(KERN_INFO "IndyCam v%d.%d detected\n",
INDYCAM_VERSION_MAJOR(camera->version),
INDYCAM_VERSION_MINOR(camera->version));
- indycam_regdump(client);
+ indycam_regdump(sd);
// initialize
- err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
+ err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq);
if (err) {
printk(KERN_ERR "IndyCam initialization failed\n");
- err = -EIO;
- goto out_detach_client;
+ kfree(camera);
+ return -EIO;
}
- indycam_regdump(client);
+ indycam_regdump(sd);
// white balance
- err = indycam_write_reg(client, INDYCAM_REG_CONTROL,
+ err = indycam_write_reg(sd, INDYCAM_REG_CONTROL,
INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
if (err) {
printk(KERN_ERR "IndyCam: White balancing camera failed\n");
- err = -EIO;
- goto out_detach_client;
+ kfree(camera);
+ return -EIO;
}
- indycam_regdump(client);
+ indycam_regdump(sd);
printk(KERN_INFO "IndyCam initialized\n");
return 0;
-
-out_detach_client:
- i2c_detach_client(client);
-out_free_camera:
- kfree(camera);
-out_free_client:
- kfree(client);
- return err;
-}
-
-static int indycam_probe(struct i2c_adapter *adap)
-{
- /* Indy specific crap */
- if (adap->id == I2C_HW_SGI_VINO)
- return indycam_attach(adap, INDYCAM_ADDR, 0);
- /* Feel free to add probe here :-) */
- return -ENODEV;
}
-static int indycam_detach(struct i2c_client *client)
+static int indycam_remove(struct i2c_client *client)
{
- struct indycam *camera = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
- i2c_detach_client(client);
- kfree(camera);
- kfree(client);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_indycam(sd));
return 0;
}
-static int indycam_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
-{
- // struct indycam *camera = i2c_get_clientdata(client);
-
- /* The old video_decoder interface just isn't enough,
- * so we'll use some custom commands. */
- switch (cmd) {
- case DECODER_GET_CAPABILITIES: {
- struct video_decoder_capability *cap = arg;
-
- cap->flags = VIDEO_DECODER_NTSC;
- cap->inputs = 1;
- cap->outputs = 1;
- break;
- }
- case DECODER_GET_STATUS: {
- int *iarg = arg;
-
- *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
- DECODER_STATUS_COLOR;
- break;
- }
- case DECODER_SET_NORM: {
- int *iarg = arg;
-
- switch (*iarg) {
- case VIDEO_MODE_NTSC:
- break;
- default:
- return -EINVAL;
- }
- break;
- }
- case DECODER_SET_INPUT: {
- int *iarg = arg;
-
- if (*iarg != 0)
- return -EINVAL;
- break;
- }
- case DECODER_SET_OUTPUT: {
- int *iarg = arg;
-
- if (*iarg != 0)
- return -EINVAL;
- break;
- }
- case DECODER_ENABLE_OUTPUT: {
- /* Always enabled */
- break;
- }
- case DECODER_SET_PICTURE: {
- // struct video_picture *pic = arg;
- /* TODO: convert values for indycam_set_controls() */
- break;
- }
- case DECODER_INDYCAM_GET_CONTROL: {
- return indycam_get_control(client, arg);
- }
- case DECODER_INDYCAM_SET_CONTROL: {
- return indycam_set_control(client, arg);
- }
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static struct i2c_driver i2c_driver_indycam = {
- .driver = {
- .name = "indycam",
- },
- .id = I2C_DRIVERID_INDYCAM,
- .attach_adapter = indycam_probe,
- .detach_client = indycam_detach,
- .command = indycam_command,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id indycam_id[] = {
+ { "indycam", 0 },
+ { }
};
+MODULE_DEVICE_TABLE(i2c, indycam_id);
-static int __init indycam_init(void)
-{
- return i2c_add_driver(&i2c_driver_indycam);
-}
-
-static void __exit indycam_exit(void)
-{
- i2c_del_driver(&i2c_driver_indycam);
-}
-
-module_init(indycam_init);
-module_exit(indycam_exit);
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "indycam",
+ .probe = indycam_probe,
+ .remove = indycam_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = indycam_id,
+#endif
+};
diff --git a/linux/drivers/media/video/indycam.h b/linux/drivers/media/video/indycam.h
index e6ee82063..881f21c47 100644
--- a/linux/drivers/media/video/indycam.h
+++ b/linux/drivers/media/video/indycam.h
@@ -87,22 +87,7 @@
/* Driver interface definitions */
-#define INDYCAM_CONTROL_AGC 0 /* boolean */
-#define INDYCAM_CONTROL_AWB 1 /* boolean */
-#define INDYCAM_CONTROL_SHUTTER 2
-#define INDYCAM_CONTROL_GAIN 3
-#define INDYCAM_CONTROL_RED_BALANCE 4
-#define INDYCAM_CONTROL_BLUE_BALANCE 5
-#define INDYCAM_CONTROL_RED_SATURATION 6
-#define INDYCAM_CONTROL_BLUE_SATURATION 7
-#define INDYCAM_CONTROL_GAMMA 8
-
-struct indycam_control {
- u8 type;
- s32 value;
-};
-
-#define DECODER_INDYCAM_GET_CONTROL _IOR('d', 193, struct indycam_control)
-#define DECODER_INDYCAM_SET_CONTROL _IOW('d', 194, struct indycam_control)
+#define INDYCAM_CONTROL_RED_SATURATION (V4L2_CID_PRIVATE_BASE + 0)
+#define INDYCAM_CONTROL_BLUE_SATURATION (V4L2_CID_PRIVATE_BASE + 1)
#endif
diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c
index a99aea49a..7bae57ad3 100644
--- a/linux/drivers/media/video/ir-kbd-i2c.c
+++ b/linux/drivers/media/video/ir-kbd-i2c.c
@@ -47,9 +47,9 @@
#include <linux/i2c-id.h>
#include <linux/workqueue.h>
+#include "compat.h"
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
-#include "compat.h"
/* ----------------------------------------------------------------------- */
/* insmod parameters */
@@ -280,12 +280,6 @@ static void ir_key_poll(struct IR_i2c *ir)
}
}
-static void ir_timer(unsigned long data)
-{
- struct IR_i2c *ir = (struct IR_i2c*)data;
- schedule_work(&ir->work);
-}
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
static void ir_work(void *data)
#else
@@ -295,7 +289,7 @@ static void ir_work(struct work_struct *work)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
struct IR_i2c *ir = data;
#else
- struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+ struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
#endif
int polling_interval = 100;
@@ -305,7 +299,7 @@ static void ir_work(struct work_struct *work)
polling_interval = 50;
ir_key_poll(ir);
- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval));
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(polling_interval));
}
/* ----------------------------------------------------------------------- */
@@ -462,14 +456,11 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
/* start polling via eventd */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- INIT_WORK(&ir->work, ir_work, ir);
+ INIT_DELAYED_WORK(&ir->work, ir_work, ir);
#else
- INIT_WORK(&ir->work, ir_work);
+ INIT_DELAYED_WORK(&ir->work, ir_work);
#endif
- init_timer(&ir->timer);
- ir->timer.function = ir_timer;
- ir->timer.data = (unsigned long)ir;
- schedule_work(&ir->work);
+ schedule_delayed_work(&ir->work, 0);
return 0;
@@ -486,8 +477,7 @@ static int ir_detach(struct i2c_client *client)
struct IR_i2c *ir = i2c_get_clientdata(client);
/* kill outstanding polls */
- del_timer_sync(&ir->timer);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&ir->work);
/* unregister devices */
input_unregister_device(ir->input);
diff --git a/linux/drivers/media/video/ivtv/ivtv-vbi.c b/linux/drivers/media/video/ivtv/ivtv-vbi.c
index 5c5d1c462..f420d31b9 100644
--- a/linux/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/linux/drivers/media/video/ivtv/ivtv-vbi.c
@@ -185,6 +185,8 @@ static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
size = 4 + ((43 * line + 3) & ~3);
} else {
memcpy(dst + sd, "itv0", 4);
+ cpu_to_le32s(&linemask[0]);
+ cpu_to_le32s(&linemask[1]);
memcpy(dst + sd + 4, &linemask[0], 8);
size = 12 + ((43 * line + 3) & ~3);
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-version.h b/linux/drivers/media/video/ivtv/ivtv-version.h
index 8cd753d30..b530dec39 100644
--- a/linux/drivers/media/video/ivtv/ivtv-version.h
+++ b/linux/drivers/media/video/ivtv/ivtv-version.h
@@ -23,7 +23,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
#define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/linux/drivers/media/video/ks0127.c b/linux/drivers/media/video/ks0127.c
index eaa481a57..3dbda6e92 100644
--- a/linux/drivers/media/video/ks0127.c
+++ b/linux/drivers/media/video/ks0127.c
@@ -589,8 +589,8 @@ static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* force to secam mode */
ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x0f);
} else {
- v4l2_dbg(1, debug, sd,
- "VIDIOC_S_STD: Unknown norm %llx\n", std);
+ v4l2_dbg(1, debug, sd, "VIDIOC_S_STD: Unknown norm %llx\n",
+ (unsigned long long)std);
}
return 0;
}
diff --git a/linux/drivers/media/video/meye.c b/linux/drivers/media/video/meye.c
index 323aa378b..11f0b5e0d 100644
--- a/linux/drivers/media/video/meye.c
+++ b/linux/drivers/media/video/meye.c
@@ -1022,7 +1022,6 @@ static int meyeioc_stilljcapt(int *len)
static int vidioc_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
- memset(cap, 0, sizeof(*cap));
strcpy(cap->driver, "meye");
strcpy(cap->card, "meye");
sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
@@ -1041,8 +1040,6 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
if (i->index != 0)
return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = 0;
strcpy(i->name, "Camera");
i->type = V4L2_INPUT_TYPE_CAMERA;
@@ -1264,22 +1261,13 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
if (f->index > 1)
return -EINVAL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
if (f->index == 0) {
/* standard YUV 422 capture */
- memset(f, 0, sizeof(*f));
- f->index = 0;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = 0;
strcpy(f->description, "YUV422");
f->pixelformat = V4L2_PIX_FMT_YUYV;
} else {
/* compressed MJPEG capture */
- memset(f, 0, sizeof(*f));
- f->index = 1;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
strcpy(f->description, "MJPEG");
f->pixelformat = V4L2_PIX_FMT_MJPEG;
@@ -1291,9 +1279,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *f)
{
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
return -EINVAL;
@@ -1324,12 +1309,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *f)
{
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
switch (meye.mchip_mode) {
case MCHIP_HIC_MODE_CONT_OUT:
default:
@@ -1346,8 +1325,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
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;
return 0;
}
@@ -1355,9 +1332,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *f)
{
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
return -EINVAL;
@@ -1403,9 +1377,6 @@ static int vidioc_reqbufs(struct file *file, void *fh,
{
int i;
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
if (req->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
@@ -1446,15 +1417,11 @@ static int vidioc_reqbufs(struct file *file, void *fh,
static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
- int index = buf->index;
+ unsigned int index = buf->index;
- if (index < 0 || index >= gbuffers)
+ if (index >= gbuffers)
return -EINVAL;
- memset(buf, 0, sizeof(*buf));
-
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->index = index;
buf->bytesused = meye.grab_buffer[index].size;
buf->flags = V4L2_BUF_FLAG_MAPPED;
@@ -1476,13 +1443,10 @@ static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
if (buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
- if (buf->index < 0 || buf->index >= gbuffers)
+ if (buf->index >= gbuffers)
return -EINVAL;
if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
@@ -1502,9 +1466,6 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
int reqnr;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
if (buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c
index 61b54317f..fdcc1c1c5 100644
--- a/linux/drivers/media/video/msp3400-driver.c
+++ b/linux/drivers/media/video/msp3400-driver.c
@@ -57,7 +57,7 @@
#else
#include <linux/freezer.h>
#endif
-#include <linux/videodev2.h>
+#include <linux/videodev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-i2c-drv-legacy.h>
@@ -371,29 +371,6 @@ int msp_sleep(struct msp_state *state, int timeout)
}
/* ------------------------------------------------------------------------ */
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
-static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
-{
- if (rxsubchans == V4L2_TUNER_SUB_MONO)
- return VIDEO_SOUND_MONO;
- if (rxsubchans == V4L2_TUNER_SUB_STEREO)
- return VIDEO_SOUND_STEREO;
- if (audmode == V4L2_TUNER_MODE_LANG2)
- return VIDEO_SOUND_LANG2;
- return VIDEO_SOUND_LANG1;
-}
-
-static int msp_mode_v4l1_to_v4l2(int mode)
-{
- if (mode & VIDEO_SOUND_STEREO)
- return V4L2_TUNER_MODE_STEREO;
- if (mode & VIDEO_SOUND_LANG2)
- return V4L2_TUNER_MODE_LANG2;
- if (mode & VIDEO_SOUND_LANG1)
- return V4L2_TUNER_MODE_LANG1;
- return V4L2_TUNER_MODE_MONO;
-}
-#endif
static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
@@ -487,96 +464,6 @@ static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return 0;
}
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
-static long msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct msp_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- switch (cmd) {
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCGAUDIO:
- {
- struct video_audio *va = arg;
-
- va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE;
- if (state->has_sound_processing)
- va->flags |= VIDEO_AUDIO_BALANCE |
- VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE;
- if (state->muted)
- va->flags |= VIDEO_AUDIO_MUTE;
- va->volume = state->volume;
- va->balance = state->volume ? state->balance : 32768;
- va->bass = state->bass;
- va->treble = state->treble;
-
- if (state->radio)
- break;
- if (state->opmode == OPMODE_AUTOSELECT)
- msp_detect_stereo(client);
- va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans, state->audmode);
- break;
- }
-
- case VIDIOCSAUDIO:
- {
- struct video_audio *va = arg;
-
- state->muted = (va->flags & VIDEO_AUDIO_MUTE);
- state->volume = va->volume;
- state->balance = va->balance;
- state->bass = va->bass;
- state->treble = va->treble;
- msp_set_audio(client);
-
- if (va->mode != 0 && state->radio == 0 &&
- state->audmode != msp_mode_v4l1_to_v4l2(va->mode)) {
- state->audmode = msp_mode_v4l1_to_v4l2(va->mode);
- msp_set_audmode(client);
- }
- break;
- }
-
- case VIDIOCSCHAN:
- {
- struct video_channel *vc = arg;
- int update = 0;
- v4l2_std_id std;
-
- if (state->radio)
- update = 1;
- state->radio = 0;
- if (vc->norm == VIDEO_MODE_PAL)
- std = V4L2_STD_PAL;
- else if (vc->norm == VIDEO_MODE_SECAM)
- std = V4L2_STD_SECAM;
- else
- std = V4L2_STD_NTSC;
- if (std != state->v4l2_std) {
- state->v4l2_std = std;
- update = 1;
- }
- if (update)
- msp_wake_thread(client);
- break;
- }
-
- case VIDIOCSFREQ:
- {
- /* new channel -- kick audio carrier scan */
- msp_wake_thread(client);
- break;
- }
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-#endif
-
/* --- v4l2 ioctls --- */
static int msp_s_radio(struct v4l2_subdev *sd)
{
@@ -827,9 +714,6 @@ static const struct v4l2_subdev_core_ops msp_core_ops = {
.g_ctrl = msp_g_ctrl,
.s_ctrl = msp_s_ctrl,
.queryctrl = msp_queryctrl,
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
- .ioctl = msp_ioctl,
-#endif
};
static const struct v4l2_subdev_tuner_ops msp_tuner_ops = {
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index c2e52100a..e3dab2119 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/log2.h>
-#include <linux/gpio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
@@ -73,9 +72,7 @@ struct mt9m001 {
struct i2c_client *client;
struct soc_camera_device icd;
int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
- int switch_gpio;
unsigned char autoexposure;
- unsigned char datawidth;
};
static int reg_read(struct soc_camera_device *icd, const u8 reg)
@@ -181,92 +178,28 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd)
return 0;
}
-static int bus_switch_request(struct mt9m001 *mt9m001,
- struct soc_camera_link *icl)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
- int ret;
- unsigned int gpio = icl->gpio;
-
- if (gpio_is_valid(gpio)) {
- /* We have a data bus switch. */
- ret = gpio_request(gpio, "mt9m001");
- if (ret < 0) {
- dev_err(&mt9m001->client->dev, "Cannot get GPIO %u\n",
- gpio);
- return ret;
- }
-
- ret = gpio_direction_output(gpio, 0);
- if (ret < 0) {
- dev_err(&mt9m001->client->dev,
- "Cannot set GPIO %u to output\n", gpio);
- gpio_free(gpio);
- return ret;
- }
- }
-
- mt9m001->switch_gpio = gpio;
-#else
- mt9m001->switch_gpio = -EINVAL;
-#endif
- return 0;
-}
-
-static void bus_switch_release(struct mt9m001 *mt9m001)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
- if (gpio_is_valid(mt9m001->switch_gpio))
- gpio_free(mt9m001->switch_gpio);
-#endif
-}
-
-static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
- if (!gpio_is_valid(mt9m001->switch_gpio))
- return -ENODEV;
-
- gpio_set_value_cansleep(mt9m001->switch_gpio, go8bit);
- return 0;
-#else
- return -ENODEV;
-#endif
-}
-
-static int bus_switch_possible(struct mt9m001 *mt9m001)
-{
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
- return gpio_is_valid(mt9m001->switch_gpio);
-#else
- return 0;
-#endif
-}
-
static int mt9m001_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
- int ret;
+ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
- /* Flags validity verified in test_bus_param */
+ /* Only one width bit may be set */
+ if (!is_power_of_2(width_flag))
+ return -EINVAL;
- if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
- (mt9m001->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
- (mt9m001->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
- /* Well, we actually only can do 10 or 8 bits... */
- if (width_flag == SOCAM_DATAWIDTH_9)
- return -EINVAL;
- ret = bus_switch_act(mt9m001,
- width_flag == SOCAM_DATAWIDTH_8);
- if (ret < 0)
- return ret;
+ if (icl->set_bus_param)
+ return icl->set_bus_param(icl, width_flag);
- mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
- }
+ /*
+ * Without board specific bus width settings we only support the
+ * sensors native bus width
+ */
+ if (width_flag == SOCAM_DATAWIDTH_10)
+ return 0;
- return 0;
+ return -EINVAL;
}
static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
@@ -274,18 +207,20 @@ 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;
/* MT9M001 has all capture_format parameters fixed */
- unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING |
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER;
- if (bus_switch_possible(mt9m001))
- flags |= SOCAM_DATAWIDTH_8;
+ if (icl->query_bus_param)
+ flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
+ else
+ flags |= SOCAM_DATAWIDTH_10;
return soc_camera_apply_sensor_flags(icl, flags);
}
-static int mt9m001_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m001_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
int ret;
@@ -324,6 +259,20 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd,
return ret;
}
+static int mt9m001_set_fmt(struct soc_camera_device *icd,
+ 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,
+ };
+
+ /* No support for scaling so far, just crop. TODO: use skipping */
+ return mt9m001_set_crop(icd, &rect);
+}
+
static int mt9m001_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
@@ -449,6 +398,7 @@ static struct soc_camera_ops mt9m001_ops = {
.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,
@@ -583,6 +533,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
s32 data;
int ret;
+ unsigned long flags;
/* We must have a parent by now. And it cannot be a wrong one.
* So this entire test is completely redundant. */
@@ -603,18 +554,10 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
case 0x8421:
mt9m001->model = V4L2_IDENT_MT9M001C12ST;
icd->formats = mt9m001_colour_formats;
- if (gpio_is_valid(icl->gpio))
- icd->num_formats = ARRAY_SIZE(mt9m001_colour_formats);
- else
- icd->num_formats = 1;
break;
case 0x8431:
mt9m001->model = V4L2_IDENT_MT9M001C12STM;
icd->formats = mt9m001_monochrome_formats;
- if (gpio_is_valid(icl->gpio))
- icd->num_formats = ARRAY_SIZE(mt9m001_monochrome_formats);
- else
- icd->num_formats = 1;
break;
default:
ret = -ENODEV;
@@ -623,6 +566,26 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
goto ei2c;
}
+ icd->num_formats = 0;
+
+ /*
+ * This is a 10bit sensor, so by default we only allow 10bit.
+ * The platform may support different bus widths due to
+ * different routing of the data lines.
+ */
+ if (icl->query_bus_param)
+ flags = icl->query_bus_param(icl);
+ else
+ flags = SOCAM_DATAWIDTH_10;
+
+ if (flags & SOCAM_DATAWIDTH_10)
+ icd->num_formats++;
+ else
+ icd->formats++;
+
+ if (flags & SOCAM_DATAWIDTH_8)
+ icd->num_formats++;
+
dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
data == 0x8431 ? "C12STM" : "C12ST");
@@ -692,18 +655,10 @@ static int mt9m001_probe(struct i2c_client *client)
icd->height_max = 1024;
icd->y_skip_top = 1;
icd->iface = icl->bus_id;
- /* Default datawidth - this is the only width this camera (normally)
- * supports. It is only with extra logic that it can support
- * other widths. Therefore it seems to be a sensible default. */
- mt9m001->datawidth = 10;
/* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width */
mt9m001->autoexposure = 1;
- ret = bus_switch_request(mt9m001, icl);
- if (ret)
- goto eswinit;
-
ret = soc_camera_device_register(icd);
if (ret)
goto eisdr;
@@ -711,8 +666,6 @@ static int mt9m001_probe(struct i2c_client *client)
return 0;
eisdr:
- bus_switch_release(mt9m001);
-eswinit:
kfree(mt9m001);
return ret;
}
@@ -722,7 +675,6 @@ static int mt9m001_remove(struct i2c_client *client)
struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
soc_camera_device_unregister(&mt9m001->icd);
- bus_switch_release(mt9m001);
kfree(mt9m001);
return 0;
diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c
index 3ae675a42..69498d519 100644
--- a/linux/drivers/media/video/mt9m111.c
+++ b/linux/drivers/media/video/mt9m111.c
@@ -152,7 +152,7 @@ struct mt9m111 {
struct soc_camera_device icd;
int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
enum mt9m111_context context;
- unsigned int left, top, width, height;
+ struct v4l2_rect rect;
u32 pixfmt;
unsigned char autoexposure;
unsigned char datawidth;
@@ -249,12 +249,13 @@ 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 soc_camera_device *icd,
+ struct v4l2_rect *rect)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
int ret, is_raw_format;
- int width = mt9m111->width;
- int height = mt9m111->height;
+ int width = rect->width;
+ int height = rect->height;
if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
|| (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
@@ -262,9 +263,9 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd)
else
is_raw_format = 0;
- ret = reg_write(COLUMN_START, mt9m111->left);
+ ret = reg_write(COLUMN_START, rect->left);
if (!ret)
- ret = reg_write(ROW_START, mt9m111->top);
+ ret = reg_write(ROW_START, rect->top);
if (is_raw_format) {
if (!ret)
@@ -436,6 +437,22 @@ 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)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ 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);
+
+ ret = mt9m111_setup_rect(icd, rect);
+ if (!ret)
+ mt9m111->rect = *rect;
+ return ret;
+}
+
static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
@@ -486,23 +503,27 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
}
static int mt9m111_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+ struct v4l2_format *f)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_rect rect = {
+ .left = mt9m111->rect.left,
+ .top = mt9m111->rect.top,
+ .width = pix->width,
+ .height = pix->height,
+ };
int ret;
- mt9m111->left = rect->left;
- mt9m111->top = rect->top;
- mt9m111->width = rect->width;
- mt9m111->height = rect->height;
-
dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
- __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width,
- mt9m111->height);
+ __func__, pix->pixelformat, rect.left, rect.top, rect.width,
+ rect.height);
- ret = mt9m111_setup_rect(icd);
+ ret = mt9m111_setup_rect(icd, &rect);
+ if (!ret)
+ ret = mt9m111_set_pixfmt(icd, pix->pixelformat);
if (!ret)
- ret = mt9m111_set_pixfmt(icd, pixfmt);
+ mt9m111->rect = rect;
return ret;
}
@@ -633,6 +654,7 @@ static struct soc_camera_ops mt9m111_ops = {
.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,
@@ -817,7 +839,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd)
mt9m111_set_context(icd, mt9m111->context);
mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
- mt9m111_setup_rect(icd);
+ 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);
diff --git a/linux/drivers/media/video/mt9t031.c b/linux/drivers/media/video/mt9t031.c
index aa0e8ec34..8a9ca0b27 100644
--- a/linux/drivers/media/video/mt9t031.c
+++ b/linux/drivers/media/video/mt9t031.c
@@ -144,8 +144,6 @@ static int mt9t031_init(struct soc_camera_device *icd)
int ret;
/* Disable chip output, synchronous option update */
- dev_dbg(icd->vdev->parent, "%s\n", __func__);
-
ret = reg_write(icd, MT9T031_RESET, 1);
if (ret >= 0)
ret = reg_write(icd, MT9T031_RESET, 0);
@@ -186,9 +184,9 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd,
return -EINVAL;
if (flags & SOCAM_PCLK_SAMPLE_FALLING)
- reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
- else
reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+ else
+ reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
return 0;
}
@@ -213,36 +211,14 @@ static void recalculate_limits(struct soc_camera_device *icd,
icd->height_max = MT9T031_MAX_HEIGHT / yskip;
}
-static int mt9t031_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9t031_set_params(struct soc_camera_device *icd,
+ struct v4l2_rect *rect, u16 xskip, u16 yskip)
{
struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
int ret;
+ u16 xbin, ybin, width, height, left, top;
const u16 hblank = MT9T031_HORIZONTAL_BLANK,
vblank = MT9T031_VERTICAL_BLANK;
- u16 xbin, xskip, ybin, yskip, width, height, left, top;
-
- if (pixfmt) {
- /*
- * 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;
-
- for (yskip = 8; yskip > 1; yskip--)
- if (rect->height * yskip <= MT9T031_MAX_HEIGHT)
- break;
-
- recalculate_limits(icd, xskip, yskip);
- } else {
- /* CROP - no change in scaling, or in limits */
- xskip = mt9t031->xskip;
- yskip = mt9t031->yskip;
- }
/* Make sure we don't exceed sensor limits */
if (rect->left + rect->width > icd->width_max)
@@ -289,7 +265,7 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
if (ret >= 0)
ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
- if (pixfmt) {
+ if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
/* Binning, skipping */
if (ret >= 0)
ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
@@ -325,15 +301,58 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
}
}
- if (!ret && pixfmt) {
+ /* Re-enable register update, commit all changes */
+ if (ret >= 0)
+ ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
+{
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+ /* CROP - no change in scaling, or in limits */
+ return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
+}
+
+static int mt9t031_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ 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,
+ };
+
+ /*
+ * 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;
+
+ for (yskip = 8; yskip > 1; yskip--)
+ if (rect.height * yskip <= MT9T031_MAX_HEIGHT)
+ break;
+
+ recalculate_limits(icd, xskip, yskip);
+
+ ret = mt9t031_set_params(icd, &rect, xskip, yskip);
+ if (!ret) {
mt9t031->xskip = xskip;
mt9t031->yskip = yskip;
}
- /* Re-enable register update, commit all changes */
- reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
-
- return ret < 0 ? ret : 0;
+ return ret;
}
static int mt9t031_try_fmt(struct soc_camera_device *icd,
@@ -470,6 +489,7 @@ static struct soc_camera_ops mt9t031_ops = {
.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,
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index 59efb8ff0..3bee30caa 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -13,7 +13,6 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/log2.h>
-#include <linux/gpio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
@@ -89,9 +88,7 @@ struct mt9v022 {
struct i2c_client *client;
struct soc_camera_device icd;
int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
- int switch_gpio;
u16 chip_control;
- unsigned char datawidth;
};
static int reg_read(struct soc_camera_device *icd, const u8 reg)
@@ -209,66 +206,6 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
return 0;
}
-static int bus_switch_request(struct mt9v022 *mt9v022, struct soc_camera_link *icl)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
- int ret;
- unsigned int gpio = icl->gpio;
-
- if (gpio_is_valid(gpio)) {
- /* We have a data bus switch. */
- ret = gpio_request(gpio, "mt9v022");
- if (ret < 0) {
- dev_err(&mt9v022->client->dev, "Cannot get GPIO %u\n", gpio);
- return ret;
- }
-
- ret = gpio_direction_output(gpio, 0);
- if (ret < 0) {
- dev_err(&mt9v022->client->dev,
- "Cannot set GPIO %u to output\n", gpio);
- gpio_free(gpio);
- return ret;
- }
- }
-
- mt9v022->switch_gpio = gpio;
-#else
- mt9v022->switch_gpio = -EINVAL;
-#endif
- return 0;
-}
-
-static void bus_switch_release(struct mt9v022 *mt9v022)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
- if (gpio_is_valid(mt9v022->switch_gpio))
- gpio_free(mt9v022->switch_gpio);
-#endif
-}
-
-static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
- if (!gpio_is_valid(mt9v022->switch_gpio))
- return -ENODEV;
-
- gpio_set_value_cansleep(mt9v022->switch_gpio, go8bit);
- return 0;
-#else
- return -ENODEV;
-#endif
-}
-
-static int bus_switch_possible(struct mt9v022 *mt9v022)
-{
-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
- return gpio_is_valid(mt9v022->switch_gpio);
-#else
- return 0;
-#endif
-}
-
static int mt9v022_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
@@ -282,19 +219,17 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
if (!is_power_of_2(width_flag))
return -EINVAL;
- if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
- (mt9v022->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
- (mt9v022->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
- /* Well, we actually only can do 10 or 8 bits... */
- if (width_flag == SOCAM_DATAWIDTH_9)
- return -EINVAL;
-
- ret = bus_switch_act(mt9v022,
- width_flag == SOCAM_DATAWIDTH_8);
- if (ret < 0)
+ if (icl->set_bus_param) {
+ ret = icl->set_bus_param(icl, width_flag);
+ if (ret)
return ret;
-
- mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+ } else {
+ /*
+ * Without board specific bus width settings we only support the
+ * sensors native bus width
+ */
+ if (width_flag != SOCAM_DATAWIDTH_10)
+ return -EINVAL;
}
flags = soc_camera_apply_sensor_flags(icl, flags);
@@ -328,10 +263,14 @@ 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);
- unsigned int width_flag = SOCAM_DATAWIDTH_10;
+ struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+ unsigned int width_flag;
- if (bus_switch_possible(mt9v022))
- width_flag |= SOCAM_DATAWIDTH_8;
+ if (icl->query_bus_param)
+ width_flag = icl->query_bus_param(icl) &
+ SOCAM_DATAWIDTH_MASK;
+ else
+ width_flag = SOCAM_DATAWIDTH_10;
return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
@@ -340,32 +279,11 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9v022_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9v022_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
int ret;
- /* The caller provides a supported format, as verified per call to
- * icd->try_fmt(), datawidth is from our supported format list */
- switch (pixfmt) {
- case V4L2_PIX_FMT_GREY:
- case V4L2_PIX_FMT_Y16:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
- return -EINVAL;
- break;
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SBGGR16:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
- return -EINVAL;
- break;
- case 0:
- /* No format change, only geometry */
- break;
- default:
- return -EINVAL;
- }
-
/* Like in example app. Contradicts the datasheet though */
ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
if (ret >= 0) {
@@ -403,6 +321,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd,
return 0;
}
+static int mt9v022_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ 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,
+ };
+
+ /* The caller provides a supported format, as verified per call to
+ * icd->try_fmt(), datawidth is from our supported format list */
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y16:
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+ return -EINVAL;
+ break;
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SBGGR16:
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+ return -EINVAL;
+ break;
+ case 0:
+ /* No format change, only geometry */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* No support for scaling on this camera, just crop. */
+ return mt9v022_set_crop(icd, &rect);
+}
+
static int mt9v022_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
@@ -544,6 +498,7 @@ static struct soc_camera_ops mt9v022_ops = {
.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,
@@ -699,6 +654,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
s32 data;
int ret;
+ unsigned long flags;
if (!icd->dev.parent ||
to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
@@ -732,22 +688,36 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
icd->formats = mt9v022_colour_formats;
- if (gpio_is_valid(icl->gpio))
- icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
- else
- icd->num_formats = 1;
} else {
ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
icd->formats = mt9v022_monochrome_formats;
- if (gpio_is_valid(icl->gpio))
- icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
- else
- icd->num_formats = 1;
}
- if (!ret)
- ret = soc_camera_video_start(icd);
+ if (ret < 0)
+ goto eisis;
+
+ icd->num_formats = 0;
+
+ /*
+ * This is a 10bit sensor, so by default we only allow 10bit.
+ * The platform may support different bus widths due to
+ * different routing of the data lines.
+ */
+ if (icl->query_bus_param)
+ flags = icl->query_bus_param(icl);
+ else
+ flags = SOCAM_DATAWIDTH_10;
+
+ if (flags & SOCAM_DATAWIDTH_10)
+ icd->num_formats++;
+ else
+ icd->formats++;
+
+ if (flags & SOCAM_DATAWIDTH_8)
+ icd->num_formats++;
+
+ ret = soc_camera_video_start(icd);
if (ret < 0)
goto eisis;
@@ -771,8 +741,12 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
soc_camera_video_stop(icd);
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static int mt9v022_probe(struct i2c_client *client,
const struct i2c_device_id *did)
+#else
+static int mt9v022_probe(struct i2c_client *client)
+#endif
{
struct mt9v022 *mt9v022;
struct soc_camera_device *icd;
@@ -812,14 +786,6 @@ static int mt9v022_probe(struct i2c_client *client,
icd->height_max = 480;
icd->y_skip_top = 1;
icd->iface = icl->bus_id;
- /* Default datawidth - this is the only width this camera (normally)
- * supports. It is only with extra logic that it can support
- * other widths. Therefore it seems to be a sensible default. */
- mt9v022->datawidth = 10;
-
- ret = bus_switch_request(mt9v022, icl);
- if (ret)
- goto eswinit;
ret = soc_camera_device_register(icd);
if (ret)
@@ -828,8 +794,6 @@ static int mt9v022_probe(struct i2c_client *client,
return 0;
eisdr:
- bus_switch_release(mt9v022);
-eswinit:
kfree(mt9v022);
return ret;
}
@@ -839,7 +803,6 @@ static int mt9v022_remove(struct i2c_client *client)
struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
soc_camera_device_unregister(&mt9v022->icd);
- bus_switch_release(mt9v022);
kfree(mt9v022);
return 0;
diff --git a/linux/drivers/media/video/mx3_camera.c b/linux/drivers/media/video/mx3_camera.c
index f525dc48f..70629e172 100644
--- a/linux/drivers/media/video/mx3_camera.c
+++ b/linux/drivers/media/video/mx3_camera.c
@@ -544,16 +544,14 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd)
}
static bool channel_change_requested(struct soc_camera_device *icd,
- const struct soc_camera_format_xlate *xlate,
- __u32 pixfmt, struct v4l2_rect *rect)
+ struct v4l2_rect *rect)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
- /* So far only one configuration is supported */
- return pixfmt || (ichan && rect->width * rect->height >
- icd->width * icd->height);
+ /* Do buffers have to be re-allocated or channel re-configured? */
+ return ichan && rect->width * rect->height > icd->width * icd->height;
}
static int test_platform_param(struct mx3_camera_dev *mx3_cam,
@@ -733,61 +731,10 @@ passthrough:
return formats;
}
-static int mx3_camera_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static void configure_geometry(struct mx3_camera_dev *mx3_cam,
+ struct v4l2_rect *rect)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
- const struct soc_camera_format_xlate *xlate;
u32 ctrl, width_field, height_field;
- int ret;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- if (pixfmt && !xlate) {
- dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
- return -EINVAL;
- }
-
- /*
- * 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, xlate, pixfmt, rect)) {
- dma_cap_mask_t mask;
- struct dma_chan *chan;
- struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
- /* We have to use IDMAC_IC_7 for Bayer / generic data */
- struct dma_chan_request rq = {.mx3_cam = mx3_cam,
- .id = IDMAC_IC_7};
-
- if (*ichan) {
- struct videobuf_buffer *vb, *_vb;
- dma_release_channel(&(*ichan)->dma_chan);
- *ichan = NULL;
- mx3_cam->active = NULL;
- list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
- list_del_init(&vb->queue);
- vb->state = VIDEOBUF_ERROR;
- wake_up(&vb->done);
- }
- }
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- dma_cap_set(DMA_PRIVATE, mask);
- chan = dma_request_channel(mask, chan_filter, &rq);
- if (!chan)
- return -EBUSY;
-
- *ichan = to_idmac_chan(chan);
- (*ichan)->client = mx3_cam;
- }
-
- /*
- * Might have to perform a complete interface initialisation like in
- * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
- * mxc_v4l2_s_fmt()
- */
/* Setup frame size - this cannot be changed on-the-fly... */
width_field = rect->width - 1;
@@ -808,9 +755,98 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
* 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)
+{
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+ struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+ /* We have to use IDMAC_IC_7 for Bayer / generic data */
+ struct dma_chan_request rq = {.mx3_cam = mx3_cam,
+ .id = IDMAC_IC_7};
+
+ if (*ichan) {
+ struct videobuf_buffer *vb, *_vb;
+ dma_release_channel(&(*ichan)->dma_chan);
+ *ichan = NULL;
+ mx3_cam->active = NULL;
+ list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_ERROR;
+ wake_up(&vb->done);
+ }
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ chan = dma_request_channel(mask, chan_filter, &rq);
+ if (!chan)
+ return -EBUSY;
+
+ *ichan = to_idmac_chan(chan);
+ (*ichan)->client = mx3_cam;
+
+ return 0;
+}
+
+static int mx3_camera_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+
+ /*
+ * 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, rect);
+
+ return icd->ops->set_crop(icd, rect);
+}
+
+static int mx3_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 mx3_camera_dev *mx3_cam = ici->priv;
+ 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);
+ return -EINVAL;
+ }
+
+ ret = acquire_dma_channel(mx3_cam);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Might have to perform a complete interface initialisation like in
+ * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
+ * mxc_v4l2_s_fmt()
+ */
+
+ configure_geometry(mx3_cam, &rect);
- ret = icd->ops->set_fmt(icd, pixfmt ? xlate->cam_fmt->fourcc : 0, rect);
- if (pixfmt && !ret) {
+ ret = icd->ops->set_fmt(icd, f);
+ if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
}
@@ -1031,6 +1067,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
.suspend = mx3_camera_suspend,
.resume = mx3_camera_resume,
#endif
+ .set_crop = mx3_camera_set_crop,
.set_fmt = mx3_camera_set_fmt,
.try_fmt = mx3_camera_try_fmt,
.get_formats = mx3_camera_get_formats,
diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c
index fda3b7581..c85cfd27e 100644
--- a/linux/drivers/media/video/mxb.c
+++ b/linux/drivers/media/video/mxb.c
@@ -25,7 +25,6 @@
#include <media/saa7146_vv.h>
#include <media/tuner.h>
-#include <linux/video_decoder.h>
#include <media/v4l2-common.h>
#include <media/saa7115.h>
#include "compat.h"
diff --git a/linux/drivers/media/video/omap24xxcam.c b/linux/drivers/media/video/omap24xxcam.c
index 73eb656ac..d828597ba 100644
--- a/linux/drivers/media/video/omap24xxcam.c
+++ b/linux/drivers/media/video/omap24xxcam.c
@@ -1285,9 +1285,6 @@ static int vidioc_g_parm(struct file *file, void *fh,
struct omap24xxcam_device *cam = ofh->cam;
int rval;
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
mutex_lock(&cam->mutex);
rval = vidioc_int_g_parm(cam->sdev, a);
mutex_unlock(&cam->mutex);
@@ -1303,9 +1300,6 @@ static int vidioc_s_parm(struct file *file, void *fh,
struct v4l2_streamparm old_streamparm;
int rval;
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
mutex_lock(&cam->mutex);
if (cam->streaming) {
rval = -EBUSY;
@@ -1665,7 +1659,6 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s)
vfd->parent = cam->dev;
strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
- vfd->vfl_type = VID_TYPE_CAPTURE | VID_TYPE_CHROMAKEY;
vfd->fops = &omap24xxcam_fops;
vfd->minor = -1;
vfd->ioctl_ops = &omap24xxcam_ioctl_fops;
diff --git a/linux/drivers/media/video/ov7670.c b/linux/drivers/media/video/ov7670.c
index e03154536..7c97449fd 100644
--- a/linux/drivers/media/video/ov7670.c
+++ b/linux/drivers/media/video/ov7670.c
@@ -12,12 +12,12 @@
*/
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/i2c.h>
#include <linux/delay.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <linux/i2c.h>
+#include <media/v4l2-i2c-drv.h>
#include "compat.h"
@@ -25,6 +25,10 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
MODULE_LICENSE("GPL");
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
/*
* Basic window sizes. These probably belong somewhere more globally
* useful.
@@ -190,11 +194,16 @@ MODULE_LICENSE("GPL");
*/
struct ov7670_format_struct; /* coming later */
struct ov7670_info {
+ struct v4l2_subdev sd;
struct ov7670_format_struct *fmt; /* Current format */
unsigned char sat; /* Saturation value */
int hue; /* Hue value */
};
+static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov7670_info, sd);
+}
@@ -401,24 +410,27 @@ static struct regval_list ov7670_fmt_raw[] = {
* Low-level register I/O.
*/
-static int ov7670_read(struct i2c_client *c, unsigned char reg,
+static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
unsigned char *value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- ret = i2c_smbus_read_byte_data(c, reg);
+ ret = i2c_smbus_read_byte_data(client, reg);
if (ret >= 0) {
- *value = (unsigned char) ret;
+ *value = (unsigned char)ret;
ret = 0;
}
return ret;
}
-static int ov7670_write(struct i2c_client *c, unsigned char reg,
+static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
unsigned char value)
{
- int ret = i2c_smbus_write_byte_data(c, reg, value);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = i2c_smbus_write_byte_data(client, reg, value);
+
if (reg == REG_COM7 && (value & COM7_RESET))
msleep(2); /* Wait for reset to run */
return ret;
@@ -426,20 +438,20 @@ static int ov7670_write(struct i2c_client *c, unsigned char reg,
#if 0 /* Not currently used, but maybe should be */
-static int ov7670_write_mask(struct i2c_client *c, unsigned char reg,
+static int ov7670_write_mask(struct v4l2_subdev *sd, unsigned char reg,
unsigned char value, unsigned char mask)
{
unsigned char v;
int ret, tries = 0;
- ret = ov7670_read(c, reg, &v);
+ ret = ov7670_read(sd, reg, &v);
if (ret < 0)
return ret;
v &= ~mask;
v |= (value & mask);
msleep(10); /* FIXME experiment */
do {
- ret = ov7670_write(c, reg, v);
+ ret = ov7670_write(sd, reg, v);
} while (ret < 0 && ++tries < 3);
return ret;
}
@@ -449,10 +461,10 @@ static int ov7670_write_mask(struct i2c_client *c, unsigned char reg,
/*
* Write a list of register settings; ff/ff stops the process.
*/
-static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
+static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals)
{
while (vals->reg_num != 0xff || vals->value != 0xff) {
- int ret = ov7670_write(c, vals->reg_num, vals->value);
+ int ret = ov7670_write(sd, vals->reg_num, vals->value);
if (ret < 0)
return ret;
vals++;
@@ -464,34 +476,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
/*
* Stuff that knows about the sensor.
*/
-static void ov7670_reset(struct i2c_client *client)
+static int ov7670_reset(struct v4l2_subdev *sd, u32 val)
{
- ov7670_write(client, REG_COM7, COM7_RESET);
+ ov7670_write(sd, REG_COM7, COM7_RESET);
msleep(1);
+ return 0;
}
-static int ov7670_init(struct i2c_client *client)
+static int ov7670_init(struct v4l2_subdev *sd, u32 val)
{
- return ov7670_write_array(client, ov7670_default_regs);
+ return ov7670_write_array(sd, ov7670_default_regs);
}
-static int ov7670_detect(struct i2c_client *client)
+static int ov7670_detect(struct v4l2_subdev *sd)
{
unsigned char v;
int ret;
- ret = ov7670_init(client);
+ ret = ov7670_init(sd, 0);
if (ret < 0)
return ret;
- ret = ov7670_read(client, REG_MIDH, &v);
+ ret = ov7670_read(sd, REG_MIDH, &v);
if (ret < 0)
return ret;
if (v != 0x7f) /* OV manuf. id. */
return -ENODEV;
- ret = ov7670_read(client, REG_MIDL, &v);
+ ret = ov7670_read(sd, REG_MIDL, &v);
if (ret < 0)
return ret;
if (v != 0xa2)
@@ -499,12 +512,12 @@ static int ov7670_detect(struct i2c_client *client)
/*
* OK, we know we have an OmniVision chip...but which one?
*/
- ret = ov7670_read(client, REG_PID, &v);
+ ret = ov7670_read(sd, REG_PID, &v);
if (ret < 0)
return ret;
if (v != 0x76) /* PID + VER = 0x76 / 0x73 */
return -ENODEV;
- ret = ov7670_read(client, REG_VER, &v);
+ ret = ov7670_read(sd, REG_VER, &v);
if (ret < 0)
return ret;
if (v != 0x73) /* PID + VER = 0x76 / 0x73 */
@@ -649,7 +662,7 @@ static struct ov7670_win_size {
/*
* Store a set of start/stop values into the camera.
*/
-static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
+static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
int vstart, int vstop)
{
int ret;
@@ -659,26 +672,26 @@ static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
* hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is
* a mystery "edge offset" value in the top two bits of href.
*/
- ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff);
- ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff);
- ret += ov7670_read(client, REG_HREF, &v);
+ ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff);
+ ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff);
+ ret += ov7670_read(sd, REG_HREF, &v);
v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
msleep(10);
- ret += ov7670_write(client, REG_HREF, v);
+ ret += ov7670_write(sd, REG_HREF, v);
/*
* Vertical: similar arrangement, but only 10 bits.
*/
- ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff);
- ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff);
- ret += ov7670_read(client, REG_VREF, &v);
+ ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff);
+ ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff);
+ ret += ov7670_read(sd, REG_VREF, &v);
v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
msleep(10);
- ret += ov7670_write(client, REG_VREF, v);
+ ret += ov7670_write(sd, REG_VREF, v);
return ret;
}
-static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
+static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
{
struct ov7670_format_struct *ofmt;
@@ -693,7 +706,8 @@ static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
}
-static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
+static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
+ struct v4l2_format *fmt,
struct ov7670_format_struct **ret_fmt,
struct ov7670_win_size **ret_wsize)
{
@@ -737,18 +751,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
return 0;
}
+static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+ return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
+}
+
/*
* Set a format.
*/
-static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
+static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{
int ret;
struct ov7670_format_struct *ovfmt;
struct ov7670_win_size *wsize;
- struct ov7670_info *info = i2c_get_clientdata(c);
- unsigned char com7, clkrc;
+ struct ov7670_info *info = to_state(sd);
+ unsigned char com7, clkrc = 0;
- ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);
+ ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
if (ret)
return ret;
/*
@@ -757,7 +776,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
* the colors.
*/
if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
- ret = ov7670_read(c, REG_CLKRC, &clkrc);
+ ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret)
return ret;
}
@@ -769,20 +788,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
*/
com7 = ovfmt->regs[0].value;
com7 |= wsize->com7_bit;
- ov7670_write(c, REG_COM7, com7);
+ ov7670_write(sd, REG_COM7, com7);
/*
* Now write the rest of the array. Also store start/stops
*/
- ov7670_write_array(c, ovfmt->regs + 1);
- ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart,
+ ov7670_write_array(sd, ovfmt->regs + 1);
+ ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
wsize->vstop);
ret = 0;
if (wsize->regs)
- ret = ov7670_write_array(c, wsize->regs);
+ ret = ov7670_write_array(sd, wsize->regs);
info->fmt = ovfmt;
if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0)
- ret = ov7670_write(c, REG_CLKRC, clkrc);
+ ret = ov7670_write(sd, REG_CLKRC, clkrc);
return ret;
}
@@ -790,7 +809,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
* Implement G/S_PARM. There is a "high quality" mode we could try
* to do someday; for now, we just do the frame rate tweak.
*/
-static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{
struct v4l2_captureparm *cp = &parms->parm.capture;
unsigned char clkrc;
@@ -798,7 +817,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- ret = ov7670_read(c, REG_CLKRC, &clkrc);
+ ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret < 0)
return ret;
memset(cp, 0, sizeof(struct v4l2_captureparm));
@@ -810,7 +829,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
return 0;
}
-static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{
struct v4l2_captureparm *cp = &parms->parm.capture;
struct v4l2_fract *tpf = &cp->timeperframe;
@@ -824,7 +843,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
/*
* CLKRC has a reserved bit, so let's preserve it.
*/
- ret = ov7670_read(c, REG_CLKRC, &clkrc);
+ ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret < 0)
return ret;
if (tpf->numerator == 0 || tpf->denominator == 0)
@@ -838,7 +857,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
clkrc = (clkrc & 0x80) | div;
tpf->numerator = 1;
tpf->denominator = OV7670_FRAME_RATE/div;
- return ov7670_write(c, REG_CLKRC, clkrc);
+ return ov7670_write(sd, REG_CLKRC, clkrc);
}
@@ -851,17 +870,17 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
/*
* Fetch and store the color matrix.
*/
-static int ov7670_get_cmatrix(struct i2c_client *client,
+static int ov7670_get_cmatrix(struct v4l2_subdev *sd,
int matrix[CMATRIX_LEN])
{
int i, ret;
unsigned char signbits;
- ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);
+ ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits);
for (i = 0; i < CMATRIX_LEN; i++) {
unsigned char raw;
- ret += ov7670_read(client, REG_CMATRIX_BASE + i, &raw);
+ ret += ov7670_read(sd, REG_CMATRIX_BASE + i, &raw);
matrix[i] = (int) raw;
if (signbits & (1 << i))
matrix[i] *= -1;
@@ -873,7 +892,7 @@ static int ov7670_get_cmatrix(struct i2c_client *client,
-static int ov7670_store_cmatrix(struct i2c_client *client,
+static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
int matrix[CMATRIX_LEN])
{
int i, ret;
@@ -883,7 +902,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
* Weird crap seems to exist in the upper part of
* the sign bits register, so let's preserve it.
*/
- ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);
+ ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits);
signbits &= 0xc0;
for (i = 0; i < CMATRIX_LEN; i++) {
@@ -902,9 +921,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
else
raw = matrix[i] & 0xff;
}
- ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw);
+ ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw);
}
- ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits);
+ ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits);
return ret;
}
@@ -987,29 +1006,29 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info,
-static int ov7670_t_sat(struct i2c_client *client, int value)
+static int ov7670_s_sat(struct v4l2_subdev *sd, int value)
{
- struct ov7670_info *info = i2c_get_clientdata(client);
+ struct ov7670_info *info = to_state(sd);
int matrix[CMATRIX_LEN];
int ret;
info->sat = value;
ov7670_calc_cmatrix(info, matrix);
- ret = ov7670_store_cmatrix(client, matrix);
+ ret = ov7670_store_cmatrix(sd, matrix);
return ret;
}
-static int ov7670_q_sat(struct i2c_client *client, __s32 *value)
+static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value)
{
- struct ov7670_info *info = i2c_get_clientdata(client);
+ struct ov7670_info *info = to_state(sd);
*value = info->sat;
return 0;
}
-static int ov7670_t_hue(struct i2c_client *client, int value)
+static int ov7670_s_hue(struct v4l2_subdev *sd, int value)
{
- struct ov7670_info *info = i2c_get_clientdata(client);
+ struct ov7670_info *info = to_state(sd);
int matrix[CMATRIX_LEN];
int ret;
@@ -1017,14 +1036,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value)
return -EINVAL;
info->hue = value;
ov7670_calc_cmatrix(info, matrix);
- ret = ov7670_store_cmatrix(client, matrix);
+ ret = ov7670_store_cmatrix(sd, matrix);
return ret;
}
-static int ov7670_q_hue(struct i2c_client *client, __s32 *value)
+static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value)
{
- struct ov7670_info *info = i2c_get_clientdata(client);
+ struct ov7670_info *info = to_state(sd);
*value = info->hue;
return 0;
@@ -1038,8 +1057,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v)
{
if ((v & 0x80) == 0)
return v + 128;
- else
- return 128 - (v & 0x7f);
+ return 128 - (v & 0x7f);
}
@@ -1047,369 +1065,279 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
{
if (v > 127)
return v & 0x7f;
- else
- return (128 - v) | 0x80;
+ return (128 - v) | 0x80;
}
-static int ov7670_t_brightness(struct i2c_client *client, int value)
+static int ov7670_s_brightness(struct v4l2_subdev *sd, int value)
{
unsigned char com8 = 0, v;
int ret;
- ov7670_read(client, REG_COM8, &com8);
+ ov7670_read(sd, REG_COM8, &com8);
com8 &= ~COM8_AEC;
- ov7670_write(client, REG_COM8, com8);
+ ov7670_write(sd, REG_COM8, com8);
v = ov7670_abs_to_sm(value);
- ret = ov7670_write(client, REG_BRIGHT, v);
+ ret = ov7670_write(sd, REG_BRIGHT, v);
return ret;
}
-static int ov7670_q_brightness(struct i2c_client *client, __s32 *value)
+static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value)
{
unsigned char v = 0;
- int ret = ov7670_read(client, REG_BRIGHT, &v);
+ int ret = ov7670_read(sd, REG_BRIGHT, &v);
*value = ov7670_sm_to_abs(v);
return ret;
}
-static int ov7670_t_contrast(struct i2c_client *client, int value)
+static int ov7670_s_contrast(struct v4l2_subdev *sd, int value)
{
- return ov7670_write(client, REG_CONTRAS, (unsigned char) value);
+ return ov7670_write(sd, REG_CONTRAS, (unsigned char) value);
}
-static int ov7670_q_contrast(struct i2c_client *client, __s32 *value)
+static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value)
{
unsigned char v = 0;
- int ret = ov7670_read(client, REG_CONTRAS, &v);
+ int ret = ov7670_read(sd, REG_CONTRAS, &v);
*value = v;
return ret;
}
-static int ov7670_q_hflip(struct i2c_client *client, __s32 *value)
+static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value)
{
int ret;
unsigned char v = 0;
- ret = ov7670_read(client, REG_MVFP, &v);
+ ret = ov7670_read(sd, REG_MVFP, &v);
*value = (v & MVFP_MIRROR) == MVFP_MIRROR;
return ret;
}
-static int ov7670_t_hflip(struct i2c_client *client, int value)
+static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
{
unsigned char v = 0;
int ret;
- ret = ov7670_read(client, REG_MVFP, &v);
+ ret = ov7670_read(sd, REG_MVFP, &v);
if (value)
v |= MVFP_MIRROR;
else
v &= ~MVFP_MIRROR;
msleep(10); /* FIXME */
- ret += ov7670_write(client, REG_MVFP, v);
+ ret += ov7670_write(sd, REG_MVFP, v);
return ret;
}
-static int ov7670_q_vflip(struct i2c_client *client, __s32 *value)
+static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value)
{
int ret;
unsigned char v = 0;
- ret = ov7670_read(client, REG_MVFP, &v);
+ ret = ov7670_read(sd, REG_MVFP, &v);
*value = (v & MVFP_FLIP) == MVFP_FLIP;
return ret;
}
-static int ov7670_t_vflip(struct i2c_client *client, int value)
+static int ov7670_s_vflip(struct v4l2_subdev *sd, int value)
{
unsigned char v = 0;
int ret;
- ret = ov7670_read(client, REG_MVFP, &v);
+ ret = ov7670_read(sd, REG_MVFP, &v);
if (value)
v |= MVFP_FLIP;
else
v &= ~MVFP_FLIP;
msleep(10); /* FIXME */
- ret += ov7670_write(client, REG_MVFP, v);
+ ret += ov7670_write(sd, REG_MVFP, v);
return ret;
}
-
-static struct ov7670_control {
- struct v4l2_queryctrl qc;
- int (*query)(struct i2c_client *c, __s32 *value);
- int (*tweak)(struct i2c_client *c, int value);
-} ov7670_controls[] =
+static int ov7670_queryctrl(struct v4l2_subdev *sd,
+ struct v4l2_queryctrl *qc)
{
- {
- .qc = {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 0x80,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .tweak = ov7670_t_brightness,
- .query = ov7670_q_brightness,
- },
- {
- .qc = {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0x40, /* XXX ov7670 spec */
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .tweak = ov7670_t_contrast,
- .query = ov7670_q_contrast,
- },
- {
- .qc = {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 256,
- .step = 1,
- .default_value = 0x80,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .tweak = ov7670_t_sat,
- .query = ov7670_q_sat,
- },
- {
- .qc = {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HUE",
- .minimum = -180,
- .maximum = 180,
- .step = 5,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .tweak = ov7670_t_hue,
- .query = ov7670_q_hue,
- },
- {
- .qc = {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .tweak = ov7670_t_vflip,
- .query = ov7670_q_vflip,
- },
- {
- .qc = {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Horizontal mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .tweak = ov7670_t_hflip,
- .query = ov7670_q_hflip,
- },
-};
-#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
+ /* Fill in min, max, step and default value for these controls. */
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
+ }
+ return -EINVAL;
+}
-static struct ov7670_control *ov7670_find_control(__u32 id)
+static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- int i;
-
- for (i = 0; i < N_CONTROLS; i++)
- if (ov7670_controls[i].qc.id == id)
- return ov7670_controls + i;
- return NULL;
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return ov7670_g_brightness(sd, &ctrl->value);
+ case V4L2_CID_CONTRAST:
+ return ov7670_g_contrast(sd, &ctrl->value);
+ case V4L2_CID_SATURATION:
+ return ov7670_g_sat(sd, &ctrl->value);
+ case V4L2_CID_HUE:
+ return ov7670_g_hue(sd, &ctrl->value);
+ case V4L2_CID_VFLIP:
+ return ov7670_g_vflip(sd, &ctrl->value);
+ case V4L2_CID_HFLIP:
+ return ov7670_g_hflip(sd, &ctrl->value);
+ }
+ return -EINVAL;
}
+static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return ov7670_s_brightness(sd, ctrl->value);
+ case V4L2_CID_CONTRAST:
+ return ov7670_s_contrast(sd, ctrl->value);
+ case V4L2_CID_SATURATION:
+ return ov7670_s_sat(sd, ctrl->value);
+ case V4L2_CID_HUE:
+ return ov7670_s_hue(sd, ctrl->value);
+ case V4L2_CID_VFLIP:
+ return ov7670_s_vflip(sd, ctrl->value);
+ case V4L2_CID_HFLIP:
+ return ov7670_s_hflip(sd, ctrl->value);
+ }
+ return -EINVAL;
+}
-static int ov7670_queryctrl(struct i2c_client *client,
- struct v4l2_queryctrl *qc)
+static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
{
- struct ov7670_control *ctrl = ov7670_find_control(qc->id);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (ctrl == NULL)
- return -EINVAL;
- *qc = ctrl->qc;
- return 0;
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
}
-static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ unsigned char val = 0;
int ret;
- if (octrl == NULL)
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
return -EINVAL;
- ret = octrl->query(client, &ctrl->value);
- if (ret >= 0)
- return 0;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ ret = ov7670_read(sd, reg->reg & 0xff, &val);
+ reg->val = val;
+ reg->size = 1;
return ret;
}
-static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
- int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (octrl == NULL)
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
return -EINVAL;
- ret = octrl->tweak(client, ctrl->value);
- if (ret >= 0)
- return 0;
- return ret;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ return 0;
}
+#endif
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops ov7670_core_ops = {
+ .g_chip_ident = ov7670_g_chip_ident,
+ .g_ctrl = ov7670_g_ctrl,
+ .s_ctrl = ov7670_s_ctrl,
+ .queryctrl = ov7670_queryctrl,
+ .reset = ov7670_reset,
+ .init = ov7670_init,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov7670_g_register,
+ .s_register = ov7670_s_register,
+#endif
+};
+static const struct v4l2_subdev_video_ops ov7670_video_ops = {
+ .enum_fmt = ov7670_enum_fmt,
+ .try_fmt = ov7670_try_fmt,
+ .s_fmt = ov7670_s_fmt,
+ .s_parm = ov7670_s_parm,
+ .g_parm = ov7670_g_parm,
+};
+static const struct v4l2_subdev_ops ov7670_ops = {
+ .core = &ov7670_core_ops,
+ .video = &ov7670_video_ops,
+};
+/* ----------------------------------------------------------------------- */
-
-/*
- * Basic i2c stuff.
- */
-static struct i2c_driver ov7670_driver;
-
-static int ov7670_attach(struct i2c_adapter *adapter)
+static int ov7670_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int ret;
- struct i2c_client *client;
+ struct v4l2_subdev *sd;
struct ov7670_info *info;
+ int ret;
- /*
- * For now: only deal with adapters we recognize.
- */
- if (adapter->id != I2C_HW_SMBUS_CAFE)
- return -ENODEV;
-
- client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL);
- if (! client)
+ info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
+ if (info == NULL)
return -ENOMEM;
- client->adapter = adapter;
- client->addr = OV7670_I2C_ADDR;
- client->driver = &ov7670_driver,
- strcpy(client->name, "OV7670");
- /*
- * Set up our info structure.
- */
- info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL);
- if (! info) {
- ret = -ENOMEM;
- goto out_free;
+ sd = &info->sd;
+ v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
+
+ /* Make sure it's an ov7670 */
+ ret = ov7670_detect(sd);
+ if (ret) {
+ v4l_dbg(1, debug, client,
+ "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
+ client->addr << 1, client->adapter->name);
+ kfree(info);
+ return ret;
}
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
info->fmt = &ov7670_formats[0];
info->sat = 128; /* Review this */
- i2c_set_clientdata(client, info);
- /*
- * Make sure it's an ov7670
- */
- ret = ov7670_detect(client);
- if (ret)
- goto out_free_info;
- ret = i2c_attach_client(client);
- if (ret)
- goto out_free_info;
return 0;
-
- out_free_info:
- kfree(info);
- out_free:
- kfree(client);
- return ret;
}
-static int ov7670_detach(struct i2c_client *client)
+static int ov7670_remove(struct i2c_client *client)
{
- i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
- kfree(client);
- return 0;
-}
-
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-static int ov7670_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
-{
- switch (cmd) {
- case VIDIOC_DBG_G_CHIP_IDENT:
- return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
-
- case VIDIOC_INT_RESET:
- ov7670_reset(client);
- return 0;
-
- case VIDIOC_INT_INIT:
- return ov7670_init(client);
-
- case VIDIOC_ENUM_FMT:
- return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg);
- case VIDIOC_TRY_FMT:
- return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL);
- case VIDIOC_S_FMT:
- return ov7670_s_fmt(client, (struct v4l2_format *) arg);
- case VIDIOC_QUERYCTRL:
- return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg);
- case VIDIOC_S_CTRL:
- return ov7670_s_ctrl(client, (struct v4l2_control *) arg);
- case VIDIOC_G_CTRL:
- return ov7670_g_ctrl(client, (struct v4l2_control *) arg);
- case VIDIOC_S_PARM:
- return ov7670_s_parm(client, (struct v4l2_streamparm *) arg);
- case VIDIOC_G_PARM:
- return ov7670_g_parm(client, (struct v4l2_streamparm *) arg);
- }
- return -EINVAL;
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
+ return 0;
}
-
-
-static struct i2c_driver ov7670_driver = {
- .driver = {
- .name = "ov7670",
- },
- .id = I2C_DRIVERID_OV7670,
- .attach_adapter = ov7670_attach,
- .detach_client = ov7670_detach,
- .command = ov7670_command,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id ov7670_id[] = {
+ { "ov7670", 0 },
+ { }
};
+MODULE_DEVICE_TABLE(i2c, ov7670_id);
-
-/*
- * Module initialization
- */
-static int __init ov7670_mod_init(void)
-{
- printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n");
- return i2c_add_driver(&ov7670_driver);
-}
-
-static void __exit ov7670_mod_exit(void)
-{
- i2c_del_driver(&ov7670_driver);
-}
-
-module_init(ov7670_mod_init);
-module_exit(ov7670_mod_exit);
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "ov7670",
+ .probe = ov7670_probe,
+ .remove = ov7670_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = ov7670_id,
+#endif
+};
diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c
index 2f3313524..cde3a1019 100644
--- a/linux/drivers/media/video/ov772x.c
+++ b/linux/drivers/media/video/ov772x.c
@@ -646,6 +646,8 @@ static int ov772x_start_capture(struct soc_camera_device *icd)
return -EPERM;
}
+ ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0);
+
dev_dbg(&icd->dev,
"format %s, win %s\n", priv->fmt->name, priv->win->name);
@@ -654,6 +656,8 @@ static int ov772x_start_capture(struct soc_camera_device *icd)
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;
}
@@ -781,11 +785,9 @@ ov772x_select_win(u32 width, u32 height)
return win;
}
-static int ov772x_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt,
- struct v4l2_rect *rect)
+static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
+ u32 pixfmt)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
int ret = -EINVAL;
u8 val;
int i;
@@ -806,7 +808,7 @@ static int ov772x_set_fmt(struct soc_camera_device *icd,
/*
* select win
*/
- priv->win = ov772x_select_win(rect->width, rect->height);
+ priv->win = ov772x_select_win(width, height);
/*
* reset hardware
@@ -870,6 +872,28 @@ ov772x_set_fmt_error:
return ret;
}
+static int ov772x_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
+{
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+
+ if (!priv->fmt)
+ return -EINVAL;
+
+ return ov772x_set_params(priv, rect->width, rect->height,
+ priv->fmt->fourcc);
+}
+
+static int ov772x_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ return ov772x_set_params(priv, pix->width, pix->height,
+ pix->pixelformat);
+}
+
static int ov772x_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
@@ -959,6 +983,7 @@ static struct soc_camera_ops ov772x_ops = {
.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,
diff --git a/linux/drivers/media/video/ovcamchip/ovcamchip_core.c b/linux/drivers/media/video/ovcamchip/ovcamchip_core.c
index c841f4e4f..63303b70f 100644
--- a/linux/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/linux/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -15,6 +15,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-i2c-drv.h>
#include "ovcamchip_priv.h"
#define DRIVER_VERSION "v2.27 for Linux 2.6"
@@ -44,6 +47,20 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = {
+ /* ov7xxx */
+ 0x42 >> 1, 0x46 >> 1, 0x4a >> 1, 0x4e >> 1,
+ 0x52 >> 1, 0x56 >> 1, 0x5a >> 1, 0x5e >> 1,
+ /* ov6xxx */
+ 0xc0 >> 1, 0xc4 >> 1, 0xc8 >> 1, 0xcc >> 1,
+ 0xd0 >> 1, 0xd4 >> 1, 0xd8 >> 1, 0xdc >> 1,
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+#endif
+
/* Registers common to all chips, that are needed for detection */
#define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
#define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */
@@ -61,10 +78,6 @@ static char *chip_names[NUM_CC_TYPES] = {
[CC_OV6630AF] = "OV6630AF",
};
-/* Forward declarations */
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
/* ----------------------------------------------------------------------- */
int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
@@ -253,112 +266,36 @@ static int ovcamchip_detect(struct i2c_client *c)
/* Test for 7xx0 */
PDEBUG(3, "Testing for 0V7xx0");
- c->addr = OV7xx0_SID;
- if (init_camchip(c) < 0) {
- /* Test for 6xx0 */
- PDEBUG(3, "Testing for 0V6xx0");
- c->addr = OV6xx0_SID;
- if (init_camchip(c) < 0) {
- return -ENODEV;
- } else {
- if (ov6xx0_detect(c) < 0) {
- PERROR("Failed to init OV6xx0");
- return -EIO;
- }
- }
- } else {
+ if (init_camchip(c) < 0)
+ return -ENODEV;
+ /* 7-bit addresses with bit 0 set are for the OV7xx0 */
+ if (c->addr & 1) {
if (ov7xx0_detect(c) < 0) {
PERROR("Failed to init OV7xx0");
return -EIO;
}
+ return 0;
+ }
+ /* Test for 6xx0 */
+ PDEBUG(3, "Testing for 0V6xx0");
+ if (ov6xx0_detect(c) < 0) {
+ PERROR("Failed to init OV6xx0");
+ return -EIO;
}
-
return 0;
}
/* ----------------------------------------------------------------------- */
-static int ovcamchip_attach(struct i2c_adapter *adap)
+static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
- int rc = 0;
- struct ovcamchip *ov;
- struct i2c_client *c;
-
- /* I2C is not a PnP bus, so we can never be certain that we're talking
- * to the right chip. To prevent damage to EEPROMS and such, only
- * attach to adapters that are known to contain OV camera chips. */
-
- switch (adap->id) {
- case I2C_HW_SMBUS_OV511:
- case I2C_HW_SMBUS_OV518:
- case I2C_HW_SMBUS_W9968CF:
- PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
- break;
- default:
- PDEBUG(1, "Adapter ID 0x%06x rejected", adap->id);
- return -ENODEV;
- }
-
- c = kmalloc(sizeof *c, GFP_KERNEL);
- if (!c) {
- rc = -ENOMEM;
- goto no_client;
- }
- memcpy(c, &client_template, sizeof *c);
- c->adapter = adap;
- strcpy(c->name, "OV????");
-
- ov = kzalloc(sizeof *ov, GFP_KERNEL);
- if (!ov) {
- rc = -ENOMEM;
- goto no_ov;
- }
- i2c_set_clientdata(c, ov);
-
- rc = ovcamchip_detect(c);
- if (rc < 0)
- goto error;
-
- strcpy(c->name, chip_names[ov->subtype]);
-
- PDEBUG(1, "Camera chip detection complete");
-
- i2c_attach_client(c);
-
- return rc;
-error:
- kfree(ov);
-no_ov:
- kfree(c);
-no_client:
- PDEBUG(1, "returning %d", rc);
- return rc;
-}
-
-static int ovcamchip_detach(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int rc;
-
- rc = ov->sops->free(c);
- if (rc < 0)
- return rc;
-
- i2c_detach_client(c);
-
- kfree(ov);
- kfree(c);
- return 0;
-}
-
-static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
+ struct ovcamchip *ov = to_ovcamchip(sd);
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
if (!ov->initialized &&
cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
cmd != OVCAMCHIP_CMD_INITIALIZE) {
- dev_err(&c->dev, "ERROR: Camera chip not initialized yet!\n");
+ v4l2_err(sd, "Camera chip not initialized yet!\n");
return -EPERM;
}
@@ -379,10 +316,10 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
if (ov->mono) {
if (ov->subtype != CC_OV7620)
- dev_warn(&c->dev, "Warning: Monochrome not "
+ v4l2_warn(sd, "Monochrome not "
"implemented for this chip\n");
else
- dev_info(&c->dev, "Initializing chip as "
+ v4l2_info(sd, "Initializing chip as "
"monochrome\n");
}
@@ -398,37 +335,84 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
}
}
+static int ovcamchip_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
/* ----------------------------------------------------------------------- */
-static struct i2c_driver driver = {
- .driver = {
- .name = "ovcamchip",
- },
- .id = I2C_DRIVERID_OVCAMCHIP,
- .attach_adapter = ovcamchip_attach,
- .detach_client = ovcamchip_detach,
- .command = ovcamchip_command,
+static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
+ .ioctl = ovcamchip_ioctl,
};
-static struct i2c_client client_template = {
- .name = "(unset)",
- .driver = &driver,
+static const struct v4l2_subdev_ops ovcamchip_ops = {
+ .core = &ovcamchip_core_ops,
};
-static int __init ovcamchip_init(void)
+static int ovcamchip_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
-#ifdef DEBUG
- ovcamchip_debug = debug;
-#endif
+ struct ovcamchip *ov;
+ struct v4l2_subdev *sd;
+ int rc = 0;
+
+ ov = kzalloc(sizeof *ov, GFP_KERNEL);
+ if (!ov) {
+ rc = -ENOMEM;
+ goto no_ov;
+ }
+ sd = &ov->sd;
+ v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
+
+ rc = ovcamchip_detect(client);
+ if (rc < 0)
+ goto error;
+
+ v4l_info(client, "%s found @ 0x%02x (%s)\n",
+ chip_names[ov->subtype], client->addr << 1, client->adapter->name);
+
+ PDEBUG(1, "Camera chip detection complete");
- PINFO(DRIVER_VERSION " : " DRIVER_DESC);
- return i2c_add_driver(&driver);
+ return rc;
+error:
+ kfree(ov);
+no_ov:
+ PDEBUG(1, "returning %d", rc);
+ return rc;
}
-static void __exit ovcamchip_exit(void)
+static int ovcamchip_remove(struct i2c_client *client)
{
- i2c_del_driver(&driver);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ovcamchip *ov = to_ovcamchip(sd);
+ int rc;
+
+ v4l2_device_unregister_subdev(sd);
+ rc = ov->sops->free(client);
+ if (rc < 0)
+ return rc;
+
+ kfree(ov);
+ return 0;
}
-module_init(ovcamchip_init);
-module_exit(ovcamchip_exit);
+/* ----------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id ovcamchip_id[] = {
+ { "ovcamchip", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "ovcamchip",
+ .command = ovcamchip_command,
+ .probe = ovcamchip_probe,
+ .remove = ovcamchip_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = ovcamchip_id,
+#endif
+};
diff --git a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
index a05650fae..4f07b78c8 100644
--- a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -16,6 +16,7 @@
#define __LINUX_OVCAMCHIP_PRIV_H
#include <linux/i2c.h>
+#include <media/v4l2-subdev.h>
#include <media/ovcamchip.h>
#ifdef DEBUG
@@ -46,6 +47,7 @@ struct ovcamchip_ops {
};
struct ovcamchip {
+ struct v4l2_subdev sd;
struct ovcamchip_ops *sops;
void *spriv; /* Private data for OV7x10.c etc... */
int subtype; /* = SEN_OV7610 etc... */
@@ -53,6 +55,11 @@ struct ovcamchip {
int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */
};
+static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ovcamchip, sd);
+}
+
extern struct ovcamchip_ops ov6x20_ops;
extern struct ovcamchip_ops ov6x30_ops;
extern struct ovcamchip_ops ov7x10_ops;
diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig
index 854c2a885..f9b6001e1 100644
--- a/linux/drivers/media/video/pvrusb2/Kconfig
+++ b/linux/drivers/media/video/pvrusb2/Kconfig
@@ -40,10 +40,10 @@ config VIDEO_PVRUSB2_DVB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
- select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
---help---
This option enables a DVB interface for the pvrusb2 driver.
diff --git a/linux/drivers/media/video/pvrusb2/Makefile b/linux/drivers/media/video/pvrusb2/Makefile
index 4fda2de69..de2fc14f0 100644
--- a/linux/drivers/media/video/pvrusb2/Makefile
+++ b/linux/drivers/media/video/pvrusb2/Makefile
@@ -2,14 +2,15 @@ obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
-pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
- pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
+pvrusb2-objs := pvrusb2-i2c-core.o \
+ pvrusb2-audio.o \
pvrusb2-encoder.o pvrusb2-video-v4l.o \
- pvrusb2-eeprom.o pvrusb2-tuner.o \
+ pvrusb2-eeprom.o \
pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+ pvrusb2-cs53l32a.o \
$(obj-pvrusb2-dvb-y) \
$(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 65babb878..61cc80ef2 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -27,14 +27,6 @@
#include <media/v4l2-common.h>
#include "compat.h"
-struct pvr2_msp3400_handler {
- struct pvr2_hdw *hdw;
- struct pvr2_i2c_client *client;
- struct pvr2_i2c_handler i2c_handler;
- unsigned long stale_mask;
-};
-
-
struct routing_scheme {
const int *def;
@@ -64,123 +56,33 @@ static const struct routing_scheme routing_schemes[] = {
},
};
-/* This function selects the correct audio input source */
-static void set_stereo(struct pvr2_msp3400_handler *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- struct v4l2_routing route;
- const struct routing_scheme *sp;
- unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
-
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
-
- if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != NULL) &&
- (hdw->input_val >= 0) &&
- (hdw->input_val < sp->cnt)) {
- route.input = sp->def[hdw->input_val];
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "*** WARNING *** i2c msp3400 v4l2 set_stereo:"
- " Invalid routing scheme (%u) and/or input (%d)",
- sid,hdw->input_val);
- return;
- }
- route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
-}
-
-
-static int check_stereo(struct pvr2_msp3400_handler *ctxt)
+void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
{
- struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->input_dirty;
-}
-
-
-struct pvr2_msp3400_ops {
- void (*update)(struct pvr2_msp3400_handler *);
- int (*check)(struct pvr2_msp3400_handler *);
-};
-
-
-static const struct pvr2_msp3400_ops msp3400_ops[] = {
- { .update = set_stereo, .check = check_stereo},
-};
-
-
-static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
- msk = 1 << idx;
- if (ctxt->stale_mask & msk) continue;
- if (msp3400_ops[idx].check(ctxt)) {
- ctxt->stale_mask |= msk;
+ if (hdw->input_dirty || hdw->force_dirty) {
+ struct v4l2_routing route;
+ const struct routing_scheme *sp;
+ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo");
+
+ if ((sid < ARRAY_SIZE(routing_schemes)) &&
+ ((sp = routing_schemes + sid) != NULL) &&
+ (hdw->input_val >= 0) &&
+ (hdw->input_val < sp->cnt)) {
+ route.input = sp->def[hdw->input_val];
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "*** WARNING *** subdev msp3400 set_input:"
+ " Invalid routing scheme (%u)"
+ " and/or input (%d)",
+ sid, hdw->input_val);
+ return;
}
+ route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+ sd->ops->audio->s_routing(sd, &route);
}
- return ctxt->stale_mask != 0;
}
-
-static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
- msk = 1 << idx;
- if (!(ctxt->stale_mask & msk)) continue;
- ctxt->stale_mask &= ~msk;
- msp3400_ops[idx].update(ctxt);
- }
-}
-
-
-static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
-{
- ctxt->client->handler = NULL;
- kfree(ctxt);
-}
-
-
-static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
- char *buf,unsigned int cnt)
-{
- return scnprintf(buf,cnt,"handler: pvrusb2-audio v4l2");
-}
-
-
-static const struct pvr2_i2c_handler_functions msp3400_funcs = {
- .detach = (void (*)(void *))pvr2_msp3400_detach,
- .check = (int (*)(void *))msp3400_check,
- .update = (void (*)(void *))msp3400_update,
- .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_msp3400_describe,
-};
-
-
-int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
- struct pvr2_msp3400_handler *ctxt;
- if (cp->handler) return 0;
-
- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
- if (!ctxt) return 0;
-
- ctxt->i2c_handler.func_data = ctxt;
- ctxt->i2c_handler.func_table = &msp3400_funcs;
- ctxt->client = cp;
- ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
- cp->handler = &ctxt->i2c_handler;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
- cp->client->addr);
- return !0;
-}
-
-
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h
index ac54eed37..e3e63d750 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h
@@ -22,10 +22,8 @@
#ifndef __PVRUSB2_AUDIO_H
#define __PVRUSB2_AUDIO_H
-#include "pvrusb2-i2c-core.h"
-
-int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
-
+#include "pvrusb2-hdw-internal.h"
+void pvr2_msp3400_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
#endif /* __PVRUSB2_AUDIO_H */
/*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
new file mode 100644
index 000000000..932943bd7
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
@@ -0,0 +1,96 @@
+/*
+ *
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * 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
+ *
+ * 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
+ *
+ */
+
+/*
+
+ This source file is specifically designed to interface with the
+ v4l-dvb cs53l32a module.
+
+*/
+
+#include "pvrusb2-cs53l32a.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include "compat.h"
+
+struct routing_scheme {
+ const int *def;
+ unsigned int cnt;
+};
+
+
+static const int routing_scheme1[] = {
+ [PVR2_CVAL_INPUT_TV] = 2, /* 1 or 2 seems to work here */
+ [PVR2_CVAL_INPUT_RADIO] = 2,
+ [PVR2_CVAL_INPUT_COMPOSITE] = 0,
+ [PVR2_CVAL_INPUT_SVIDEO] = 0,
+};
+
+static const struct routing_scheme routing_schemes[] = {
+ [PVR2_ROUTING_SCHEME_ONAIR] = {
+ .def = routing_scheme1,
+ .cnt = ARRAY_SIZE(routing_scheme1),
+ },
+};
+
+
+void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
+{
+ if (hdw->input_dirty || hdw->force_dirty) {
+ struct v4l2_routing route;
+ const struct routing_scheme *sp;
+ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
+ hdw->input_val);
+ if ((sid < ARRAY_SIZE(routing_schemes)) &&
+ ((sp = routing_schemes + sid) != NULL) &&
+ (hdw->input_val >= 0) &&
+ (hdw->input_val < sp->cnt)) {
+ route.input = sp->def[hdw->input_val];
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "*** WARNING *** subdev v4l2 set_input:"
+ " Invalid routing scheme (%u)"
+ " and/or input (%d)",
+ sid, hdw->input_val);
+ return;
+ }
+ route.output = 0;
+ sd->ops->audio->s_routing(sd, &route);
+ }
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h
index ef4afaf37..53ba548b7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h
@@ -2,6 +2,7 @@
*
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
*
* 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
@@ -17,14 +18,24 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#ifndef __PVRUSB2_TUNER_H
-#define __PVRUSB2_TUNER_H
-#include "pvrusb2-i2c-core.h"
+#ifndef __PVRUSB2_CS53L32A_H
+#define __PVRUSB2_CS53L32A_H
-int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+/*
+
+ This module connects the pvrusb2 driver to the I2C chip level
+ driver which handles device video processing. This interface is
+ used internally by the driver; higher level code should only
+ interact through the interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+#include "pvrusb2-hdw-internal.h"
+void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
-#endif /* __PVRUSB2_TUNER_H */
+#endif /* __PVRUSB2_AUDIO_CS53L32A_H */
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index 2f051f797..e0a6de5ae 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -28,7 +28,6 @@
#include "pvrusb2-cx2584x-v4l.h"
#include "pvrusb2-video-v4l.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
#include "pvrusb2-hdw-internal.h"
@@ -40,14 +39,6 @@
#include <linux/slab.h>
#include "compat.h"
-struct pvr2_v4l_cx2584x {
- struct pvr2_i2c_handler handler;
- struct pvr2_decoder_ctrl ctrl;
- struct pvr2_i2c_client *client;
- struct pvr2_hdw *hdw;
- unsigned long stale_mask;
-};
-
struct routing_scheme_item {
int vid;
@@ -111,218 +102,44 @@ static const struct routing_scheme routing_schemes[] = {
},
};
-static void set_input(struct pvr2_v4l_cx2584x *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- struct v4l2_routing route;
- enum cx25840_video_input vid_input;
- enum cx25840_audio_input aud_input;
- const struct routing_scheme *sp;
- unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
-
- memset(&route,0,sizeof(route));
-
- if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != NULL) &&
- (hdw->input_val >= 0) &&
- (hdw->input_val < sp->cnt)) {
- vid_input = sp->def[hdw->input_val].vid;
- aud_input = sp->def[hdw->input_val].aud;
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "*** WARNING *** i2c cx2584x set_input:"
- " Invalid routing scheme (%u) and/or input (%d)",
- sid,hdw->input_val);
- return;
- }
-
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
- vid_input,aud_input);
- route.input = (u32)vid_input;
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
- route.input = (u32)aud_input;
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
-}
-
-
-static int check_input(struct pvr2_v4l_cx2584x *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->input_dirty != 0;
-}
-
-
-static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
-{
- u32 val;
- struct pvr2_hdw *hdw = ctxt->hdw;
-
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d",
- hdw->srate_val);
- switch (hdw->srate_val) {
- default:
- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
- val = 48000;
- break;
- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
- val = 44100;
- break;
- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
- val = 32000;
- break;
- }
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
-}
-
-
-static int check_audio(struct pvr2_v4l_cx2584x *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->srate_dirty != 0;
-}
-
-
-struct pvr2_v4l_cx2584x_ops {
- void (*update)(struct pvr2_v4l_cx2584x *);
- int (*check)(struct pvr2_v4l_cx2584x *);
-};
-
-
-static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
- { .update = set_input, .check = check_input},
- { .update = set_audio, .check = check_audio},
-};
-
-
-static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
+void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
{
- ctxt->client->handler = NULL;
- pvr2_hdw_set_decoder(ctxt->hdw,NULL);
- kfree(ctxt);
-}
-
-
-static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
- msk = 1 << idx;
- if (ctxt->stale_mask & msk) continue;
- if (decoder_ops[idx].check(ctxt)) {
- ctxt->stale_mask |= msk;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev cx2584x update...");
+ if (hdw->input_dirty || hdw->force_dirty) {
+ struct v4l2_routing route;
+ enum cx25840_video_input vid_input;
+ enum cx25840_audio_input aud_input;
+ const struct routing_scheme *sp;
+ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+
+ memset(&route, 0, sizeof(route));
+
+ if ((sid < ARRAY_SIZE(routing_schemes)) &&
+ ((sp = routing_schemes + sid) != NULL) &&
+ (hdw->input_val >= 0) &&
+ (hdw->input_val < sp->cnt)) {
+ vid_input = sp->def[hdw->input_val].vid;
+ aud_input = sp->def[hdw->input_val].aud;
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "*** WARNING *** subdev cx2584x set_input:"
+ " Invalid routing scheme (%u)"
+ " and/or input (%d)",
+ sid, hdw->input_val);
+ return;
}
- }
- return ctxt->stale_mask != 0;
-}
-
-static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
- msk = 1 << idx;
- if (!(ctxt->stale_mask & msk)) continue;
- ctxt->stale_mask &= ~msk;
- decoder_ops[idx].update(ctxt);
+ pvr2_trace(PVR2_TRACE_CHIPS,
+ "subdev cx2584x set_input vid=0x%x aud=0x%x",
+ vid_input, aud_input);
+ route.input = (u32)vid_input;
+ sd->ops->video->s_routing(sd, &route);
+ route.input = (u32)aud_input;
+ sd->ops->audio->s_routing(sd, &route);
}
}
-static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl)
-{
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl);
- pvr2_v4l2_cmd_stream(ctxt->client,fl);
-}
-
-
-static int decoder_detect(struct pvr2_i2c_client *cp)
-{
- int ret;
- /* Attempt to query the decoder - let's see if it will answer */
- struct v4l2_queryctrl qc;
-
- memset(&qc,0,sizeof(qc));
-
- qc.id = V4L2_CID_BRIGHTNESS;
-
- ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc);
- return ret == 0; /* Return true if it answered */
-}
-
-
-static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
- char *buf,unsigned int cnt)
-{
- return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l");
-}
-
-
-static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
-{
- int ret;
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL);
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
-}
-
-
-static const struct pvr2_i2c_handler_functions hfuncs = {
- .detach = (void (*)(void *))decoder_detach,
- .check = (int (*)(void *))decoder_check,
- .update = (void (*)(void *))decoder_update,
- .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
-};
-
-
-int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
- struct pvr2_i2c_client *cp)
-{
- struct pvr2_v4l_cx2584x *ctxt;
-
- if (hdw->decoder_ctrl) return 0;
- if (cp->handler) return 0;
- if (!decoder_detect(cp)) return 0;
-
- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
- if (!ctxt) return 0;
-
- ctxt->handler.func_data = ctxt;
- ctxt->handler.func_table = &hfuncs;
- ctxt->ctrl.ctxt = ctxt;
- ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
- ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
- ctxt->client = cp;
- ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
- pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
- cp->handler = &ctxt->handler;
- {
- /*
- Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit
- of nuttiness for cx25840 causes that module to
- correctly set up its video scaling. This is really
- a problem in the cx25840 module itself, but we work
- around it here. The problem has not been seen in
- ivtv because there VBI is supported and set up. We
- don't do VBI here (at least not yet) and thus we
- never attempted to even set it up.
- */
- struct v4l2_format fmt;
- memset(&fmt,0,sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_FMT,&fmt);
- }
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
- cp->client->addr);
- return !0;
-}
-
-
-
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
index 66abf77f5..e35c2322a 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -34,9 +34,9 @@
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
-int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+void pvr2_cx25840_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
#endif /* __PVRUSB2_CX2584X_V4L_H */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index ca892fb78..fbe3856bd 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -23,7 +23,6 @@
#include "pvrusb2-debugifc.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
-#include "pvrusb2-i2c-core.h"
struct debugifc_mask_item {
const char *name;
@@ -147,10 +146,6 @@ int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
- ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
- bcnt += ccnt; acnt -= ccnt; buf += ccnt;
- ccnt = pvr2_i2c_report(hdw,buf,acnt);
- bcnt += ccnt; acnt -= ccnt; buf += ccnt;
return bcnt;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
index e24ff59f8..2f8d46761 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
@@ -22,16 +22,16 @@
struct pvr2_hdw;
-/* Non-intrusively print some useful debugging info from inside the
- driver. This should work even if the driver appears to be
- wedged. */
-int pvr2_debugifc_print_info(struct pvr2_hdw *,
- char *buf_ptr,unsigned int buf_size);
-
/* Print general status of driver. This will also trigger a probe of
the USB link. Unlike print_info(), this one synchronizes with the
driver so the information should be self-consistent (but it will
hang if the driver is wedged). */
+int pvr2_debugifc_print_info(struct pvr2_hdw *,
+ char *buf_ptr, unsigned int buf_size);
+
+/* Non-intrusively print some useful debugging info from inside the
+ driver. This should work even if the driver appears to be
+ wedged. */
int pvr2_debugifc_print_status(struct pvr2_hdw *,
char *buf_ptr,unsigned int buf_size);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index cbe2a3417..1cb6a260e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -46,10 +46,11 @@ pvr2_device_desc structures.
/*------------------------------------------------------------------------*/
/* Hauppauge PVR-USB2 Model 29xxx */
-static const char *pvr2_client_29xxx[] = {
- "msp3400",
- "saa7115",
- "tuner",
+static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = {
+ { .module_id = PVR2_CLIENT_ID_SAA7115 },
+ { .module_id = PVR2_CLIENT_ID_MSP3400 },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
+ { .module_id = PVR2_CLIENT_ID_DEMOD },
};
static const char *pvr2_fw1_names_29xxx[] = {
@@ -59,8 +60,8 @@ static const char *pvr2_fw1_names_29xxx[] = {
static const struct pvr2_device_desc pvr2_device_29xxx = {
.description = "WinTV PVR USB2 Model Category 29xxx",
.shortname = "29xxx",
- .client_modules.lst = pvr2_client_29xxx,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
+ .client_table.lst = pvr2_cli_29xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_29xxx),
.fx2_firmware.lst = pvr2_fw1_names_29xxx,
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
.flag_has_hauppauge_rom = !0,
@@ -77,10 +78,11 @@ static const struct pvr2_device_desc pvr2_device_29xxx = {
/*------------------------------------------------------------------------*/
/* Hauppauge PVR-USB2 Model 24xxx */
-static const char *pvr2_client_24xxx[] = {
- "cx25840",
- "tuner",
- "wm8775",
+static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
+ { .module_id = PVR2_CLIENT_ID_WM8775 },
+ { .module_id = PVR2_CLIENT_ID_DEMOD },
};
static const char *pvr2_fw1_names_24xxx[] = {
@@ -90,8 +92,8 @@ static const char *pvr2_fw1_names_24xxx[] = {
static const struct pvr2_device_desc pvr2_device_24xxx = {
.description = "WinTV PVR USB2 Model Category 24xxx",
.shortname = "24xxx",
- .client_modules.lst = pvr2_client_24xxx,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
+ .client_table.lst = pvr2_cli_24xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_24xxx),
.fx2_firmware.lst = pvr2_fw1_names_24xxx,
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
.flag_has_cx25840 = !0,
@@ -111,16 +113,16 @@ static const struct pvr2_device_desc pvr2_device_24xxx = {
/*------------------------------------------------------------------------*/
/* GOTVIEW USB2.0 DVD2 */
-static const char *pvr2_client_gotview_2[] = {
- "cx25840",
- "tuner",
+static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
};
static const struct pvr2_device_desc pvr2_device_gotview_2 = {
.description = "Gotview USB 2.0 DVD 2",
.shortname = "gv2",
- .client_modules.lst = pvr2_client_gotview_2,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+ .client_table.lst = pvr2_cli_gotview_2,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
.flag_has_cx25840 = !0,
.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.flag_has_analogtuner = !0,
@@ -140,8 +142,8 @@ static const struct pvr2_device_desc pvr2_device_gotview_2 = {
static const struct pvr2_device_desc pvr2_device_gotview_2d = {
.description = "Gotview USB 2.0 DVD Deluxe",
.shortname = "gv2d",
- .client_modules.lst = pvr2_client_gotview_2,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+ .client_table.lst = pvr2_cli_gotview_2,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
.flag_has_cx25840 = !0,
.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.flag_has_analogtuner = !0,
@@ -181,29 +183,29 @@ static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
return 0;
}
-static struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+static const struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
.frontend_attach = pvr2_lgdt3303_attach,
.tuner_attach = pvr2_lgh06xf_attach,
};
#endif
-static const char *pvr2_client_onair_creator[] = {
- "saa7115",
- "tuner",
- "cs53l32a",
+static const struct pvr2_device_client_desc pvr2_cli_onair_creator[] = {
+ { .module_id = PVR2_CLIENT_ID_SAA7115 },
+ { .module_id = PVR2_CLIENT_ID_CS53L32A },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
};
static const struct pvr2_device_desc pvr2_device_onair_creator = {
.description = "OnAir Creator Hybrid USB tuner",
.shortname = "oac",
- .client_modules.lst = pvr2_client_onair_creator,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
+ .client_table.lst = pvr2_cli_onair_creator,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_creator),
.default_tuner_type = TUNER_LG_TDVS_H06XF,
.flag_has_analogtuner = !0,
.flag_has_composite = !0,
.flag_has_svideo = !0,
.flag_digital_requires_cx23416 = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
.digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
.default_std_mask = V4L2_STD_NTSC_M,
#ifdef CONFIG_VIDEO_PVRUSB2_DVB
@@ -241,29 +243,29 @@ static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
return 0;
}
-static struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+static const struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
.frontend_attach = pvr2_lgdt3302_attach,
.tuner_attach = pvr2_fcv1236d_attach,
};
#endif
-static const char *pvr2_client_onair_usb2[] = {
- "saa7115",
- "tuner",
- "cs53l32a",
+static const struct pvr2_device_client_desc pvr2_cli_onair_usb2[] = {
+ { .module_id = PVR2_CLIENT_ID_SAA7115 },
+ { .module_id = PVR2_CLIENT_ID_CS53L32A },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
};
static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
.description = "OnAir USB2 Hybrid USB tuner",
.shortname = "oa2",
- .client_modules.lst = pvr2_client_onair_usb2,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
+ .client_table.lst = pvr2_cli_onair_usb2,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_usb2),
.default_tuner_type = TUNER_PHILIPS_FCV1236D,
.flag_has_analogtuner = !0,
.flag_has_composite = !0,
.flag_has_svideo = !0,
.flag_digital_requires_cx23416 = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
.digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
.default_std_mask = V4L2_STD_NTSC_M,
#ifdef CONFIG_VIDEO_PVRUSB2_DVB
@@ -314,15 +316,16 @@ static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
return 0;
}
-static struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+static const struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
.frontend_attach = pvr2_tda10048_attach,
.tuner_attach = pvr2_73xxx_tda18271_8295_attach,
};
#endif
-static const char *pvr2_client_73xxx[] = {
- "cx25840",
- "tuner",
+static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+ { .module_id = PVR2_CLIENT_ID_TUNER,
+ .i2c_address_list = "\x42"},
};
static const char *pvr2_fw1_names_73xxx[] = {
@@ -332,8 +335,8 @@ static const char *pvr2_fw1_names_73xxx[] = {
static const struct pvr2_device_desc pvr2_device_73xxx = {
.description = "WinTV HVR-1900 Model Category 73xxx",
.shortname = "73xxx",
- .client_modules.lst = pvr2_client_73xxx,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx),
+ .client_table.lst = pvr2_cli_73xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
.fx2_firmware.lst = pvr2_fw1_names_73xxx,
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx),
.flag_has_cx25840 = !0,
@@ -418,22 +421,17 @@ static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
return 0;
}
-static struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+static const struct pvr2_dvb_props pvr2_750xx_dvb_props = {
.frontend_attach = pvr2_s5h1409_attach,
.tuner_attach = pvr2_tda18271_8295_attach,
};
-static struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+static const struct pvr2_dvb_props pvr2_751xx_dvb_props = {
.frontend_attach = pvr2_s5h1411_attach,
.tuner_attach = pvr2_tda18271_8295_attach,
};
#endif
-static const char *pvr2_client_75xxx[] = {
- "cx25840",
- "tuner",
-};
-
static const char *pvr2_fw1_names_75xxx[] = {
"v4l-pvrusb2-73xxx-01.fw",
};
@@ -441,8 +439,8 @@ static const char *pvr2_fw1_names_75xxx[] = {
static const struct pvr2_device_desc pvr2_device_750xx = {
.description = "WinTV HVR-1950 Model Category 750xx",
.shortname = "750xx",
- .client_modules.lst = pvr2_client_75xxx,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+ .client_table.lst = pvr2_cli_73xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
.fx2_firmware.lst = pvr2_fw1_names_75xxx,
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
.flag_has_cx25840 = !0,
@@ -463,8 +461,8 @@ static const struct pvr2_device_desc pvr2_device_750xx = {
static const struct pvr2_device_desc pvr2_device_751xx = {
.description = "WinTV HVR-1950 Model Category 751xx",
.shortname = "751xx",
- .client_modules.lst = pvr2_client_75xxx,
- .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+ .client_table.lst = pvr2_cli_73xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
.fx2_firmware.lst = pvr2_fw1_names_75xxx,
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
.flag_has_cx25840 = !0,
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index cb3a33eb0..3e553389c 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -33,6 +33,34 @@
*/
+#define PVR2_CLIENT_ID_NULL 0
+#define PVR2_CLIENT_ID_MSP3400 1
+#define PVR2_CLIENT_ID_CX25840 2
+#define PVR2_CLIENT_ID_SAA7115 3
+#define PVR2_CLIENT_ID_TUNER 4
+#define PVR2_CLIENT_ID_CS53L32A 5
+#define PVR2_CLIENT_ID_WM8775 6
+#define PVR2_CLIENT_ID_DEMOD 7
+
+struct pvr2_device_client_desc {
+ /* One ovr PVR2_CLIENT_ID_xxxx */
+ unsigned char module_id;
+
+ /* Null-terminated array of I2C addresses to try in order
+ initialize the module. It's safe to make this null terminated
+ since we're never going to encounter an i2c device with an
+ address of zero. If this is a null pointer or zero-length,
+ then no I2C addresses have been specified, in which case we'll
+ try some compiled in defaults for now. */
+ unsigned char *i2c_address_list;
+};
+
+struct pvr2_device_client_table {
+ const struct pvr2_device_client_desc *lst;
+ unsigned char cnt;
+};
+
+
struct pvr2_string_table {
const char **lst;
unsigned int cnt;
@@ -40,6 +68,7 @@ struct pvr2_string_table {
#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
#define PVR2_ROUTING_SCHEME_GOTVIEW 1
+#define PVR2_ROUTING_SCHEME_ONAIR 2
#define PVR2_DIGITAL_SCHEME_NONE 0
#define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
@@ -66,6 +95,9 @@ struct pvr2_device_desc {
/* List of additional client modules we need to load */
struct pvr2_string_table client_modules;
+ /* List of defined client modules we need to load */
+ struct pvr2_device_client_table client_table;
+
/* List of FX2 firmware file names we should search; if empty then
FX2 firmware check / load is skipped and we assume the device
was initialized from internal ROM. */
@@ -73,7 +105,7 @@ struct pvr2_device_desc {
#ifdef CONFIG_VIDEO_PVRUSB2_DVB
/* callback functions to handle attachment of digital tuner & demod */
- struct pvr2_dvb_props *dvb_props;
+ const struct pvr2_dvb_props *dvb_props;
#endif
/* Initial standard bits to use for this device, if not zero.
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c
index 29d18e867..14decf216 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -326,7 +326,7 @@ static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
{
struct pvr2_hdw *hdw = adap->channel.hdw;
- struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
+ const struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
int ret = 0;
if (dvb_props == NULL) {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 744bc192c..452981827 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -380,7 +380,7 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
int encMisc3Arg = 0;
#if 0 /* keep */
- /* This inexplicable bit happens in the Hauppage windows
+ /* This inexplicable bit happens in the Hauppauge windows
driver (for both 24xxx and 29xxx devices). However I
currently see no difference in behavior with or without
this stuff. Leave this here as a note of its existence,
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index d96f0f510..5d75eb521 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -38,6 +38,7 @@
#include <linux/mutex.h>
#include "pvrusb2-hdw.h"
#include "pvrusb2-io.h"
+#include <media/v4l2-device.h>
#include <media/cx2341x.h>
#include "pvrusb2-devattr.h"
@@ -57,8 +58,6 @@
#define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0)
#define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0)
-struct pvr2_decoder;
-
typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
@@ -139,22 +138,6 @@ struct pvr2_ctrl {
};
-struct pvr2_decoder_ctrl {
- void *ctxt;
- void (*detach)(void *);
- void (*enable)(void *,int);
- void (*force_reset)(void *);
-};
-
-#define PVR2_I2C_PEND_DETECT 0x01 /* Need to detect a client type */
-#define PVR2_I2C_PEND_CLIENT 0x02 /* Client needs a specific update */
-#define PVR2_I2C_PEND_REFRESH 0x04 /* Client has specific pending bits */
-#define PVR2_I2C_PEND_STALE 0x08 /* Broadcast pending bits */
-
-#define PVR2_I2C_PEND_ALL (PVR2_I2C_PEND_DETECT |\
- PVR2_I2C_PEND_CLIENT |\
- PVR2_I2C_PEND_REFRESH |\
- PVR2_I2C_PEND_STALE)
/* Disposition of firmware1 loading situation */
#define FW1_STATE_UNKNOWN 0
@@ -179,6 +162,8 @@ struct pvr2_hdw {
struct usb_device *usb_dev;
struct usb_interface *usb_intf;
+ /* Our handle into the v4l2 sub-device architecture */
+ struct v4l2_device v4l2_dev;
/* Device description, anything that must adjust behavior based on
device specific info will use information held here. */
const struct pvr2_device_desc *hdw_desc;
@@ -186,7 +171,6 @@ struct pvr2_hdw {
/* Kernel worker thread handling */
struct workqueue_struct *workqueue;
struct work_struct workpoll; /* Update driver state */
- struct work_struct worki2csync; /* Update i2c clients */
/* Video spigot */
struct pvr2_stream *vid_stream;
@@ -215,12 +199,6 @@ struct pvr2_hdw {
pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT];
int i2c_cx25840_hack_state;
int i2c_linked;
- unsigned int i2c_pend_types; /* Which types of update are needed */
- unsigned long i2c_pend_mask; /* Change bits we need to scan */
- unsigned long i2c_stale_mask; /* Pending broadcast change bits */
- unsigned long i2c_active_mask; /* All change bits currently in use */
- struct list_head i2c_clients;
- struct mutex i2c_list_lock;
/* Frequency table */
unsigned int freqTable[FREQTABLE_SIZE];
@@ -287,6 +265,7 @@ struct pvr2_hdw {
wait_queue_head_t state_wait_data;
+ int force_dirty; /* consider all controls dirty if true */
int flag_ok; /* device in known good state */
int flag_disconnected; /* flag_ok == 0 due to disconnect */
int flag_init_ok; /* true if structure is fully initialized */
@@ -295,17 +274,13 @@ struct pvr2_hdw {
int flag_decoder_missed;/* We've noticed missing decoder */
int flag_tripped; /* Indicates overall failure to start */
- struct pvr2_decoder_ctrl *decoder_ctrl;
+ unsigned int decoder_client_id;
// CPU firmware info (used to help find / save firmware data)
char *fw_buffer;
unsigned int fw_size;
int fw_cpu_flag; /* True if we are dealing with the CPU */
- // True if there is a request to trigger logging of state in each
- // module.
- int log_requested;
-
/* Tuner / frequency control stuff */
unsigned int tuner_type;
int tuner_updated;
@@ -403,7 +378,8 @@ struct pvr2_hdw {
/* This function gets the current frequency */
unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
-void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
+
+void pvr2_hdw_status_poll(struct pvr2_hdw *);
#endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 19e12c5aa..bea17cd64 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -24,17 +24,22 @@
#include <linux/firmware.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
+#include <media/tuner.h>
#include "pvrusb2.h"
#include "pvrusb2-std.h"
#include "pvrusb2-util.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-i2c-core.h"
-#include "pvrusb2-tuner.h"
#include "pvrusb2-eeprom.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-encoder.h"
#include "pvrusb2-debug.h"
#include "pvrusb2-fx2-cmd.h"
+#include "pvrusb2-wm8775.h"
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-cs53l32a.h"
+#include "pvrusb2-audio.h"
#include "compat.h"
#define TV_MIN_FREQ 55250000L
@@ -105,6 +110,39 @@ MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
/* size of a firmware chunk */
#define FIRMWARE_CHUNK_SIZE 0x2000
+typedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *,
+ struct v4l2_subdev *);
+
+static const pvr2_subdev_update_func pvr2_module_update_functions[] = {
+ [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update,
+ [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update,
+ [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update,
+ [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update,
+ [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update,
+};
+
+static const char *module_names[] = {
+ [PVR2_CLIENT_ID_MSP3400] = "msp3400",
+ [PVR2_CLIENT_ID_CX25840] = "cx25840",
+ [PVR2_CLIENT_ID_SAA7115] = "saa7115",
+ [PVR2_CLIENT_ID_TUNER] = "tuner",
+ [PVR2_CLIENT_ID_DEMOD] = "tuner",
+ [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a",
+ [PVR2_CLIENT_ID_WM8775] = "wm8775",
+};
+
+
+static const unsigned char *module_i2c_addresses[] = {
+ [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63",
+ [PVR2_CLIENT_ID_DEMOD] = "\x43",
+ [PVR2_CLIENT_ID_MSP3400] = "\x40",
+ [PVR2_CLIENT_ID_SAA7115] = "\x21",
+ [PVR2_CLIENT_ID_WM8775] = "\x1b",
+ [PVR2_CLIENT_ID_CX25840] = "\x44",
+ [PVR2_CLIENT_ID_CS53L32A] = "\x11",
+};
+
+
/* Define the list of additional controls we'll dynamically construct based
on query of the cx2341x module. */
struct pvr2_mpeg_ids {
@@ -278,7 +316,6 @@ static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
static void pvr2_hdw_state_sched(struct pvr2_hdw *);
static int pvr2_hdw_state_eval(struct pvr2_hdw *);
static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
-static void pvr2_hdw_worker_i2c(struct work_struct *work);
static void pvr2_hdw_worker_poll(struct work_struct *work);
static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
@@ -643,7 +680,7 @@ static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
unsigned long fv;
struct pvr2_hdw *hdw = cptr->hdw;
if (hdw->tuner_signal_stale) {
- pvr2_i2c_core_status_poll(hdw);
+ pvr2_hdw_status_poll(hdw);
}
fv = hdw->tuner_signal_info.rangehigh;
if (!fv) {
@@ -665,7 +702,7 @@ static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
unsigned long fv;
struct pvr2_hdw *hdw = cptr->hdw;
if (hdw->tuner_signal_stale) {
- pvr2_i2c_core_status_poll(hdw);
+ pvr2_hdw_status_poll(hdw);
}
fv = hdw->tuner_signal_info.rangelow;
if (!fv) {
@@ -859,7 +896,7 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
{
struct pvr2_hdw *hdw = cptr->hdw;
- pvr2_i2c_core_status_poll(hdw);
+ pvr2_hdw_status_poll(hdw);
*vp = hdw->tuner_signal_info.signal;
return 0;
}
@@ -869,7 +906,7 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
int val = 0;
unsigned int subchan;
struct pvr2_hdw *hdw = cptr->hdw;
- pvr2_i2c_core_status_poll(hdw);
+ pvr2_hdw_status_poll(hdw);
subchan = hdw->tuner_signal_info.rxsubchans;
if (subchan & V4L2_TUNER_SUB_MONO) {
val |= (1 << V4L2_TUNER_MODE_MONO);
@@ -1650,33 +1687,27 @@ static const char *pvr2_get_state_name(unsigned int st)
static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
{
- if (!hdw->decoder_ctrl) {
- if (!hdw->flag_decoder_missed) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: No decoder present");
- hdw->flag_decoder_missed = !0;
- trace_stbit("flag_decoder_missed",
- hdw->flag_decoder_missed);
- }
- return -EIO;
+ /* Even though we really only care about the video decoder chip at
+ this point, we'll broadcast stream on/off to all sub-devices
+ anyway, just in case somebody else wants to hear the
+ command... */
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
+ (enablefl ? "on" : "off"));
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
+ if (hdw->decoder_client_id) {
+ /* We get here if the encoder has been noticed. Otherwise
+ we'll issue a warning to the user (which should
+ normally never happen). */
+ return 0;
}
- hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
- return 0;
-}
-
-
-void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
-{
- if (hdw->decoder_ctrl == ptr) return;
- hdw->decoder_ctrl = ptr;
- if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
- hdw->flag_decoder_missed = 0;
+ if (!hdw->flag_decoder_missed) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING: No decoder present");
+ hdw->flag_decoder_missed = !0;
trace_stbit("flag_decoder_missed",
hdw->flag_decoder_missed);
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Decoder has appeared");
- pvr2_hdw_state_sched(hdw);
}
+ return -EIO;
}
@@ -1950,6 +1981,166 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
}
+static unsigned int pvr2_copy_i2c_addr_list(
+ unsigned short *dst, const unsigned char *src,
+ unsigned int dst_max)
+{
+ unsigned int cnt = 0;
+ if (!src) return 0;
+ while (src[cnt] && (cnt + 1) < dst_max) {
+ dst[cnt] = src[cnt];
+ cnt++;
+ }
+ dst[cnt] = I2C_CLIENT_END;
+ return cnt;
+}
+
+
+static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
+ const struct pvr2_device_client_desc *cd)
+{
+ const char *fname;
+ unsigned char mid;
+ struct v4l2_subdev *sd;
+ unsigned int i2ccnt;
+ const unsigned char *p;
+ /* Arbitrary count - max # i2c addresses we will probe */
+ unsigned short i2caddr[25];
+
+ mid = cd->module_id;
+ fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL;
+ if (!fname) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Module ID %u for device %s has no name",
+ mid,
+ hdw->hdw_desc->description);
+ return -EINVAL;
+ }
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Module ID %u (%s) for device %s being loaded...",
+ mid, fname,
+ hdw->hdw_desc->description);
+
+ i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list,
+ ARRAY_SIZE(i2caddr));
+ if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ?
+ module_i2c_addresses[mid] : NULL) != NULL)) {
+ /* Second chance: Try default i2c address list */
+ i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p,
+ ARRAY_SIZE(i2caddr));
+ if (i2ccnt) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Module ID %u:"
+ " Using default i2c address list",
+ mid);
+ }
+ }
+
+ if (!i2ccnt) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Module ID %u (%s) for device %s:"
+ " No i2c addresses",
+ mid, fname, hdw->hdw_desc->description);
+ return -EINVAL;
+ }
+
+ /* Note how the 2nd and 3rd arguments are the same for both
+ * v4l2_i2c_new_subdev() and v4l2_i2c_new_probed_subdev(). Why?
+ * Well the 2nd argument is the module name to load, while the 3rd
+ * argument is documented in the framework as being the "chipid" -
+ * and every other place where I can find examples of this, the
+ * "chipid" appears to just be the module name again. So here we
+ * just do the same thing. */
+ if (i2ccnt == 1) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Module ID %u:"
+ " Setting up with specified i2c address 0x%x",
+ mid, i2caddr[0]);
+ sd = v4l2_i2c_new_subdev(&hdw->i2c_adap,
+ fname, fname,
+ i2caddr[0]);
+ } else {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Module ID %u:"
+ " Setting up with address probe list",
+ mid);
+ sd = v4l2_i2c_new_probed_subdev(&hdw->i2c_adap,
+ fname, fname,
+ i2caddr);
+ }
+
+ if (!sd) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Module ID %u (%s) for device %s failed to load",
+ mid, fname, hdw->hdw_desc->description);
+ return -EIO;
+ }
+
+ /* Tag this sub-device instance with the module ID we know about.
+ In other places we'll use that tag to determine if the instance
+ requires special handling. */
+ sd->grp_id = mid;
+
+ pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname);
+
+
+ /* client-specific setup... */
+ switch (mid) {
+ case PVR2_CLIENT_ID_CX25840:
+ hdw->decoder_client_id = mid;
+ {
+ /*
+ Mike Isely <isely@pobox.com> 19-Nov-2006 - This
+ bit of nuttiness for cx25840 causes that module
+ to correctly set up its video scaling. This is
+ really a problem in the cx25840 module itself,
+ but we work around it here. The problem has not
+ been seen in ivtv because there VBI is supported
+ and set up. We don't do VBI here (at least not
+ yet) and thus we never attempted to even set it
+ up.
+ */
+ struct v4l2_format fmt;
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Module ID %u:"
+ " Executing cx25840 VBI hack",
+ mid);
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ v4l2_device_call_all(&hdw->v4l2_dev, mid,
+ video, s_fmt, &fmt);
+ }
+ break;
+ case PVR2_CLIENT_ID_SAA7115:
+ hdw->decoder_client_id = mid;
+ break;
+ default: break;
+ }
+
+ return 0;
+}
+
+
+static void pvr2_hdw_load_modules(struct pvr2_hdw *hdw)
+{
+ unsigned int idx;
+ const struct pvr2_string_table *cm;
+ const struct pvr2_device_client_table *ct;
+ int okFl = !0;
+
+ cm = &hdw->hdw_desc->client_modules;
+ for (idx = 0; idx < cm->cnt; idx++) {
+ request_module(cm->lst[idx]);
+ }
+
+ ct = &hdw->hdw_desc->client_table;
+ for (idx = 0; idx < ct->cnt; idx++) {
+ if (pvr2_hdw_load_subdev(hdw, &ct->lst[idx]) < 0) okFl = 0;
+ }
+ if (!okFl) pvr2_hdw_render_useless(hdw);
+}
+
+
static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
{
int ret;
@@ -1989,9 +2180,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
if (!pvr2_hdw_dev_ok(hdw)) return;
- for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
- request_module(hdw->hdw_desc->client_modules.lst[idx]);
- }
+ hdw->force_dirty = !0;
if (!hdw->hdw_desc->flag_no_powerup) {
pvr2_hdw_cmd_powerup(hdw);
@@ -2010,6 +2199,11 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
pvr2_i2c_core_init(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
+ pvr2_hdw_load_modules(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, init, 0);
+
for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
cptr = hdw->controls + idx;
if (cptr->info->skip_init) continue;
@@ -2068,8 +2262,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
hdw->tuner_type);
}
- pvr2_i2c_core_check_stale(hdw);
- hdw->tuner_updated = 0;
if (!pvr2_hdw_dev_ok(hdw)) return;
@@ -2207,11 +2399,14 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
struct pvr2_hdw *hdw = NULL;
int valid_std_mask;
struct pvr2_ctrl *cptr;
+ struct usb_device *usb_dev;
const struct pvr2_device_desc *hdw_desc;
__u8 ifnum;
struct v4l2_queryctrl qctrl;
struct pvr2_ctl_info *ciptr;
+ usb_dev = interface_to_usbdev(intf);
+
hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
if (hdw_desc == NULL) {
@@ -2396,6 +2591,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
if (!hdw->ctl_read_urb) goto fail;
+ if (v4l2_device_register(&usb_dev->dev, &hdw->v4l2_dev) != 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Error registering with v4l core, giving up");
+ goto fail;
+ }
mutex_lock(&pvr2_unit_mtx); do {
for (idx = 0; idx < PVR_NUM; idx++) {
if (unit_pointers[idx]) continue;
@@ -2420,11 +2620,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
INIT_WORK(&hdw->workpoll,(void (*)(void*))pvr2_hdw_worker_poll,
&hdw->workpoll);
- INIT_WORK(&hdw->worki2csync,(void (*)(void*))pvr2_hdw_worker_i2c,
- &hdw->worki2csync);
#else
INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
- INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
#endif
pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
@@ -2434,7 +2631,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->flag_ok = !0;
hdw->usb_intf = intf;
- hdw->usb_dev = interface_to_usbdev(intf);
+ hdw->usb_dev = usb_dev;
usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info));
@@ -2494,6 +2691,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
hdw->ctl_write_buffer = NULL;
}
hdw->flag_disconnected = !0;
+ /* If we don't do this, then there will be a dangling struct device
+ reference to our disappearing device persisting inside the V4L
+ core... */
+ v4l2_device_disconnect(&hdw->v4l2_dev);
hdw->usb_dev = NULL;
hdw->usb_intf = NULL;
pvr2_hdw_render_useless(hdw);
@@ -2521,10 +2722,8 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- if (hdw->decoder_ctrl) {
- hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
- }
pvr2_i2c_core_done(hdw);
+ v4l2_device_unregister(&hdw->v4l2_dev);
pvr2_hdw_remove_usb_stuff(hdw);
mutex_lock(&pvr2_unit_mtx); do {
if ((hdw->unit_number >= 0) &&
@@ -2718,6 +2917,150 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
}
+static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
+ const char *name, int val)
+{
+ struct v4l2_control ctrl;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 %s=%d", name, val);
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = id;
+ ctrl.value = val;
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, s_ctrl, &ctrl);
+}
+
+#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \
+ if ((hdw)->lab##_dirty || (hdw)->force_dirty) { \
+ pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
+ }
+
+/* Execute whatever commands are required to update the state of all the
+ sub-devices so that they match our current control values. */
+static void pvr2_subdev_update(struct pvr2_hdw *hdw)
+{
+ struct v4l2_subdev *sd;
+ unsigned int id;
+ pvr2_subdev_update_func fp;
+
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev update...");
+
+ if (hdw->tuner_updated || hdw->force_dirty) {
+ struct tuner_setup setup;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)",
+ hdw->tuner_type);
+ if (((int)(hdw->tuner_type)) >= 0) {
+ setup.addr = ADDR_UNSET;
+ setup.type = hdw->tuner_type;
+ setup.mode_mask = T_RADIO | T_ANALOG_TV;
+ v4l2_device_call_all(&hdw->v4l2_dev, 0,
+ tuner, s_type_addr, &setup);
+ }
+ }
+
+ if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) {
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard");
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ v4l2_device_call_all(&hdw->v4l2_dev, 0,
+ tuner, s_radio);
+ } else {
+ v4l2_std_id vs;
+ vs = hdw->std_mask_cur;
+ v4l2_device_call_all(&hdw->v4l2_dev, 0,
+ tuner, s_std, vs);
+ }
+ hdw->tuner_signal_stale = !0;
+ hdw->cropcap_stale = !0;
+ }
+
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_BRIGHTNESS, brightness);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_CONTRAST, contrast);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_SATURATION, saturation);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_HUE, hue);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_MUTE, mute);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_VOLUME, volume);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BALANCE, balance);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass);
+ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble);
+
+ if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) {
+ struct v4l2_tuner vt;
+ memset(&vt, 0, sizeof(vt));
+ vt.audmode = hdw->audiomode_val;
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt);
+ }
+
+ if (hdw->freqDirty || hdw->force_dirty) {
+ unsigned long fv;
+ struct v4l2_frequency freq;
+ fv = pvr2_hdw_get_cur_freq(hdw);
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_freq(%lu)", fv);
+ if (hdw->tuner_signal_stale) pvr2_hdw_status_poll(hdw);
+ memset(&freq, 0, sizeof(freq));
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ /* ((fv * 1000) / 62500) */
+ freq.frequency = (fv * 2) / 125;
+ } else {
+ freq.frequency = fv / 62500;
+ }
+ /* tuner-core currently doesn't seem to care about this, but
+ let's set it anyway for completeness. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ freq.type = V4L2_TUNER_RADIO;
+ } else {
+ freq.type = V4L2_TUNER_ANALOG_TV;
+ }
+ freq.tuner = 0;
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner,
+ s_frequency, &freq);
+ }
+
+ if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) {
+ struct v4l2_format fmt;
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = hdw->res_hor_val;
+ fmt.fmt.pix.height = hdw->res_ver_val;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
+ fmt.fmt.pix.width, fmt.fmt.pix.height);
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt);
+ }
+
+ if (hdw->srate_dirty || hdw->force_dirty) {
+ u32 val;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d",
+ hdw->srate_val);
+ switch (hdw->srate_val) {
+ default:
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+ val = 48000;
+ break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+ val = 44100;
+ break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+ val = 32000;
+ break;
+ }
+ v4l2_device_call_all(&hdw->v4l2_dev, 0,
+ audio, s_clock_freq, val);
+ }
+
+ /* Unable to set crop parameters; there is apparently no equivalent
+ for VIDIOC_S_CROP */
+
+ v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+ id = sd->grp_id;
+ if (id >= ARRAY_SIZE(pvr2_module_update_functions)) continue;
+ fp = pvr2_module_update_functions[id];
+ if (!fp) continue;
+ (*fp)(hdw, sd);
+ }
+
+ if (hdw->tuner_signal_stale || hdw->cropcap_stale) {
+ pvr2_hdw_status_poll(hdw);
+ }
+}
+
+
/* Figure out if we need to commit control changes. If so, mark internal
state flags to indicate this fact and return true. Otherwise do nothing
else and return false. */
@@ -2726,7 +3069,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
unsigned int idx;
struct pvr2_ctrl *cptr;
int value;
- int commit_flag = 0;
+ int commit_flag = hdw->force_dirty;
char buf[100];
unsigned int bcnt,ccnt;
@@ -2882,18 +3225,6 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
}
- /* Scan i2c core at this point - before we clear all the dirty
- bits. Various parts of the i2c core will notice dirty bits as
- appropriate and arrange to broadcast or directly send updates to
- the client drivers in order to keep everything in sync */
- pvr2_i2c_core_check_stale(hdw);
-
- for (idx = 0; idx < hdw->control_cnt; idx++) {
- cptr = hdw->controls + idx;
- if (!cptr->info->clear_dirty) continue;
- cptr->info->clear_dirty(cptr);
- }
-
if (hdw->active_stream_type != hdw->desired_stream_type) {
/* Handle any side effects of stream config here */
hdw->active_stream_type = hdw->desired_stream_type;
@@ -2913,8 +3244,16 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
}
}
- /* Now execute i2c core update */
- pvr2_i2c_core_sync(hdw);
+ /* Check and update state for all sub-devices. */
+ pvr2_subdev_update(hdw);
+
+ hdw->tuner_updated = 0;
+ hdw->force_dirty = 0;
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ if (!cptr->info->clear_dirty) continue;
+ cptr->info->clear_dirty(cptr);
+ }
if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) &&
hdw->state_encoder_run) {
@@ -2944,15 +3283,6 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
}
-static void pvr2_hdw_worker_i2c(struct work_struct *work)
-{
- struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_i2c_core_sync(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
static void pvr2_hdw_worker_poll(struct work_struct *work)
{
int fl = 0;
@@ -3013,7 +3343,7 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
{
LOCK_TAKE(hdw->big_lock); do {
- pvr2_i2c_core_status_poll(hdw);
+ pvr2_hdw_status_poll(hdw);
} while (0); LOCK_GIVE(hdw->big_lock);
}
@@ -3023,7 +3353,7 @@ static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw)
if (!hdw->cropcap_stale) {
return 0;
}
- pvr2_i2c_core_status_poll(hdw);
+ pvr2_hdw_status_poll(hdw);
if (hdw->cropcap_stale) {
return -EIO;
}
@@ -3050,7 +3380,7 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
{
LOCK_TAKE(hdw->big_lock); do {
if (hdw->tuner_signal_stale) {
- pvr2_i2c_core_status_poll(hdw);
+ pvr2_hdw_status_poll(hdw);
}
memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
} while (0); LOCK_GIVE(hdw->big_lock);
@@ -3069,11 +3399,8 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
{
int nr = pvr2_hdw_get_unit_number(hdw);
LOCK_TAKE(hdw->big_lock); do {
- hdw->log_requested = !0;
printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
- pvr2_i2c_core_check_stale(hdw);
- hdw->log_requested = 0;
- pvr2_i2c_core_sync(hdw);
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status);
pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
pvr2_hdw_state_log_state(hdw);
@@ -3828,22 +4155,16 @@ int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
{
- if (!hdw->decoder_ctrl) {
- pvr2_trace(PVR2_TRACE_INIT,
- "Unable to reset decoder: nothing attached");
- return -ENOTTY;
- }
-
- if (!hdw->decoder_ctrl->force_reset) {
- pvr2_trace(PVR2_TRACE_INIT,
- "Unable to reset decoder: not implemented");
- return -ENOTTY;
- }
-
pvr2_trace(PVR2_TRACE_INIT,
"Requesting decoder reset");
- hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
- return 0;
+ if (hdw->decoder_client_id) {
+ v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
+ core, reset, 0);
+ return 0;
+ }
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Unable to reset decoder: nothing attached");
+ return -ENOTTY;
}
@@ -4588,6 +4909,79 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
}
+/* Generate report containing info about attached sub-devices and attached
+ i2c clients, including an indication of which attached i2c clients are
+ actually sub-devices. */
+static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw,
+ char *buf, unsigned int acnt)
+{
+ struct v4l2_subdev *sd;
+ unsigned int tcnt = 0;
+ unsigned int ccnt;
+ struct i2c_client *client;
+ struct list_head *item;
+ void *cd;
+ const char *p;
+ unsigned int id;
+
+ ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:");
+ tcnt += ccnt;
+ v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+ id = sd->grp_id;
+ p = NULL;
+ if (id < ARRAY_SIZE(module_names)) p = module_names[id];
+ if (p) {
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p);
+ tcnt += ccnt;
+ } else {
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+ " (unknown id=%u)", id);
+ tcnt += ccnt;
+ }
+ }
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+ tcnt += ccnt;
+
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n");
+ tcnt += ccnt;
+
+ mutex_lock(&hdw->i2c_adap.clist_lock);
+ list_for_each(item, &hdw->i2c_adap.clients) {
+ client = list_entry(item, struct i2c_client, list);
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+ " %s: i2c=%02x", client->name, client->addr);
+ tcnt += ccnt;
+ cd = i2c_get_clientdata(client);
+ v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+ if (cd == sd) {
+ id = sd->grp_id;
+ p = NULL;
+ if (id < ARRAY_SIZE(module_names)) {
+ p = module_names[id];
+ }
+ if (p) {
+ ccnt = scnprintf(buf + tcnt,
+ acnt - tcnt,
+ " subdev=%s", p);
+ tcnt += ccnt;
+ } else {
+ ccnt = scnprintf(buf + tcnt,
+ acnt - tcnt,
+ " subdev= id %u)",
+ id);
+ tcnt += ccnt;
+ }
+ break;
+ }
+ }
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+ tcnt += ccnt;
+ }
+ mutex_unlock(&hdw->i2c_adap.clist_lock);
+ return tcnt;
+}
+
+
unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
char *buf,unsigned int acnt)
{
@@ -4602,6 +4996,8 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
buf[0] = '\n'; ccnt = 1;
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
}
+ ccnt = pvr2_hdw_report_clients(hdw, buf, acnt);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
LOCK_GIVE(hdw->big_lock);
return bcnt;
}
@@ -4609,14 +5005,25 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
{
- char buf[128];
- unsigned int idx,ccnt;
+ char buf[256];
+ unsigned int idx, ccnt;
+ unsigned int lcnt, ucnt;
for (idx = 0; ; idx++) {
ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
if (!ccnt) break;
printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
}
+ ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf));
+ ucnt = 0;
+ while (ucnt < ccnt) {
+ lcnt = 0;
+ while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) {
+ lcnt++;
+ }
+ printk(KERN_INFO "%s %.*s\n", hdw->name, lcnt, buf + ucnt);
+ ucnt += lcnt + 1;
+ }
}
@@ -4796,6 +5203,30 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
}
+void pvr2_hdw_status_poll(struct pvr2_hdw *hdw)
+{
+ struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+ memset(vtp, 0, sizeof(*vtp));
+ hdw->tuner_signal_stale = 0;
+ /* Note: There apparently is no replacement for VIDIOC_CROPCAP
+ using v4l2-subdev - therefore we can't support that AT ALL right
+ now. (Of course, no sub-drivers seem to implement it either.
+ But now it's a a chicken and egg problem...) */
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner,
+ &hdw->tuner_signal_info);
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll"
+ " type=%u strength=%u audio=0x%x cap=0x%x"
+ " low=%u hi=%u",
+ vtp->type,
+ vtp->signal, vtp->rxsubchans, vtp->capability,
+ vtp->rangelow, vtp->rangehigh);
+
+ /* We have to do this to avoid getting into constant polling if
+ there's nobody to answer a poll of cropcap info. */
+ hdw->cropcap_stale = 0;
+}
+
+
unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
{
return hdw->input_avail_mask;
@@ -4891,7 +5322,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
int setFl, u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
- struct pvr2_i2c_client *cp;
struct v4l2_dbg_register req;
int stat = 0;
int okFl = 0;
@@ -4901,21 +5331,9 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
req.match = *match;
req.reg = reg_id;
if (setFl) req.val = *val_ptr;
- mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- if (!v4l2_chip_match_i2c_client(
- cp->client,
- &req.match)) {
- continue;
- }
- stat = pvr2_i2c_client_cmd(
- cp,(setFl ? VIDIOC_DBG_S_REGISTER :
- VIDIOC_DBG_G_REGISTER),&req);
- if (!setFl) *val_ptr = req.val;
- okFl = !0;
- break;
- }
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+ /* It would be nice to know if a sub-device answered the request */
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req);
+ if (!setFl) *val_ptr = req.val;
if (okFl) {
return stat;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
deleted file mode 100644
index 073b02a4b..000000000
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * 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
- *
- */
-
-#include <linux/kernel.h>
-#include "pvrusb2-i2c-core.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-debug.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
-#include "pvrusb2-audio.h"
-#include "pvrusb2-tuner.h"
-#include "pvrusb2-video-v4l.h"
-#include "pvrusb2-cx2584x-v4l.h"
-#include "pvrusb2-wm8775.h"
-#include "compat.h"
-
-#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
-
-#define OP_INIT 0 /* MUST come first so it is run first */
-#define OP_STANDARD 1
-#define OP_AUDIOMODE 2
-#define OP_BCSH 3
-#define OP_VOLUME 4
-#define OP_FREQ 5
-#define OP_AUDIORATE 6
-#define OP_CROP 7
-#define OP_SIZE 8
-#define OP_LOG 9
-
-static const struct pvr2_i2c_op * const ops[] = {
- [OP_INIT] = &pvr2_i2c_op_v4l2_init,
- [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
- [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
- [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
- [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
- [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
- [OP_CROP] = &pvr2_i2c_op_v4l2_crop,
- [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
- [OP_LOG] = &pvr2_i2c_op_v4l2_log,
-};
-
-void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
- int id;
- id = cp->client->driver->id;
- cp->ctl_mask = ((1 << OP_INIT) |
- (1 << OP_STANDARD) |
- (1 << OP_AUDIOMODE) |
- (1 << OP_BCSH) |
- (1 << OP_VOLUME) |
- (1 << OP_FREQ) |
- (1 << OP_CROP) |
- (1 << OP_SIZE) |
- (1 << OP_LOG));
- cp->status_poll = pvr2_v4l2_cmd_status_poll;
-
- if (id == I2C_DRIVERID_MSP3400) {
- if (pvr2_i2c_msp3400_setup(hdw,cp)) {
- return;
- }
- }
- if (id == I2C_DRIVERID_TUNER) {
- if (pvr2_i2c_tuner_setup(hdw,cp)) {
- return;
- }
- }
- if (id == I2C_DRIVERID_CX25840) {
- if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
- return;
- }
- }
- if (id == I2C_DRIVERID_WM8775) {
- if (pvr2_i2c_wm8775_setup(hdw,cp)) {
- return;
- }
- }
- if (id == I2C_DRIVERID_SAA711X) {
- if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
- return;
- }
- }
-}
-
-
-const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
-{
- if (idx >= ARRAY_SIZE(ops))
- return NULL;
- return ops[idx];
-}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
deleted file mode 100644
index db61c1fb0..000000000
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
- * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * 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
- *
- * 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
- *
- */
-
-#include "pvrusb2-i2c-cmd-v4l2.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-debug.h"
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include "compat.h"
-
-static void execute_init(struct pvr2_hdw *hdw)
-{
- u32 dummy = 0;
- pvr2_trace(PVR2_TRACE_CHIPS, "i2c v4l2 init");
- pvr2_i2c_core_cmd(hdw, VIDIOC_INT_INIT, &dummy);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_init = {
- .update = execute_init,
- .name = "v4l2_init",
-};
-
-
-static void set_standard(struct pvr2_hdw *hdw)
-{
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard");
-
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- pvr2_i2c_core_cmd(hdw,AUDC_SET_RADIO,NULL);
- } else {
- v4l2_std_id vs;
- vs = hdw->std_mask_cur;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
- }
- hdw->tuner_signal_stale = !0;
- hdw->cropcap_stale = !0;
-}
-
-
-static int check_standard(struct pvr2_hdw *hdw)
-{
- return (hdw->input_dirty != 0) || (hdw->std_dirty != 0);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard = {
- .check = check_standard,
- .update = set_standard,
- .name = "v4l2_standard",
-};
-
-
-static void set_bcsh(struct pvr2_hdw *hdw)
-{
- struct v4l2_control ctrl;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh"
- " b=%d c=%d s=%d h=%d",
- hdw->brightness_val,hdw->contrast_val,
- hdw->saturation_val,hdw->hue_val);
- memset(&ctrl,0,sizeof(ctrl));
- ctrl.id = V4L2_CID_BRIGHTNESS;
- ctrl.value = hdw->brightness_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
- ctrl.id = V4L2_CID_CONTRAST;
- ctrl.value = hdw->contrast_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
- ctrl.id = V4L2_CID_SATURATION;
- ctrl.value = hdw->saturation_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
- ctrl.id = V4L2_CID_HUE;
- ctrl.value = hdw->hue_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-}
-
-
-static int check_bcsh(struct pvr2_hdw *hdw)
-{
- return (hdw->brightness_dirty ||
- hdw->contrast_dirty ||
- hdw->saturation_dirty ||
- hdw->hue_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh = {
- .check = check_bcsh,
- .update = set_bcsh,
- .name = "v4l2_bcsh",
-};
-
-
-static void set_volume(struct pvr2_hdw *hdw)
-{
- struct v4l2_control ctrl;
- pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_volume"
- "(vol=%d bal=%d bas=%d treb=%d mute=%d)",
- hdw->volume_val,
- hdw->balance_val,
- hdw->bass_val,
- hdw->treble_val,
- hdw->mute_val);
- memset(&ctrl,0,sizeof(ctrl));
- ctrl.id = V4L2_CID_AUDIO_MUTE;
- ctrl.value = hdw->mute_val ? 1 : 0;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
- ctrl.id = V4L2_CID_AUDIO_VOLUME;
- ctrl.value = hdw->volume_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
- ctrl.id = V4L2_CID_AUDIO_BALANCE;
- ctrl.value = hdw->balance_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
- ctrl.id = V4L2_CID_AUDIO_BASS;
- ctrl.value = hdw->bass_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
- ctrl.id = V4L2_CID_AUDIO_TREBLE;
- ctrl.value = hdw->treble_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
-}
-
-
-static int check_volume(struct pvr2_hdw *hdw)
-{
- return (hdw->volume_dirty ||
- hdw->balance_dirty ||
- hdw->bass_dirty ||
- hdw->treble_dirty ||
- hdw->mute_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
- .check = check_volume,
- .update = set_volume,
- .name = "v4l2_volume",
-};
-
-
-static void set_audiomode(struct pvr2_hdw *hdw)
-{
- struct v4l2_tuner vt;
- memset(&vt,0,sizeof(vt));
- vt.audmode = hdw->audiomode_val;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
-}
-
-
-static int check_audiomode(struct pvr2_hdw *hdw)
-{
- return (hdw->input_dirty ||
- hdw->audiomode_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
- .check = check_audiomode,
- .update = set_audiomode,
- .name = "v4l2_audiomode",
-};
-
-
-static void set_frequency(struct pvr2_hdw *hdw)
-{
- unsigned long fv;
- struct v4l2_frequency freq;
- fv = pvr2_hdw_get_cur_freq(hdw);
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
- if (hdw->tuner_signal_stale) {
- pvr2_i2c_core_status_poll(hdw);
- }
- memset(&freq,0,sizeof(freq));
- if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
- // ((fv * 1000) / 62500)
- freq.frequency = (fv * 2) / 125;
- } else {
- freq.frequency = fv / 62500;
- }
- /* tuner-core currently doesn't seem to care about this, but
- let's set it anyway for completeness. */
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- freq.type = V4L2_TUNER_RADIO;
- } else {
- freq.type = V4L2_TUNER_ANALOG_TV;
- }
- freq.tuner = 0;
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
-}
-
-
-static int check_frequency(struct pvr2_hdw *hdw)
-{
- return hdw->freqDirty != 0;
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency = {
- .check = check_frequency,
- .update = set_frequency,
- .name = "v4l2_freq",
-};
-
-
-static void set_size(struct pvr2_hdw *hdw)
-{
- struct v4l2_format fmt;
-
- memset(&fmt,0,sizeof(fmt));
-
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = hdw->res_hor_val;
- fmt.fmt.pix.height = hdw->res_ver_val;
-
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)",
- fmt.fmt.pix.width,fmt.fmt.pix.height);
-
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_FMT,&fmt);
-}
-
-
-static int check_size(struct pvr2_hdw *hdw)
-{
- return (hdw->res_hor_dirty || hdw->res_ver_dirty);
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
- .check = check_size,
- .update = set_size,
- .name = "v4l2_size",
-};
-
-
-static void set_crop(struct pvr2_hdw *hdw)
-{
- struct v4l2_crop crop;
-
- memset(&crop, 0, sizeof crop);
- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- crop.c.left = hdw->cropl_val;
- crop.c.top = hdw->cropt_val;
- crop.c.height = hdw->croph_val;
- crop.c.width = hdw->cropw_val;
-
- pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_crop crop=%d:%d:%d:%d",
- crop.c.width, crop.c.height, crop.c.left, crop.c.top);
-
- pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
-}
-
-static int check_crop(struct pvr2_hdw *hdw)
-{
- return (hdw->cropl_dirty || hdw->cropt_dirty ||
- hdw->cropw_dirty || hdw->croph_dirty);
-}
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop = {
- .check = check_crop,
- .update = set_crop,
- .name = "v4l2_crop",
-};
-
-
-static void do_log(struct pvr2_hdw *hdw)
-{
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
- pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,NULL);
-
-}
-
-
-static int check_log(struct pvr2_hdw *hdw)
-{
- return hdw->log_requested != 0;
-}
-
-
-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = {
- .check = check_log,
- .update = do_log,
- .name = "v4l2_log",
-};
-
-
-void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
-{
- pvr2_i2c_client_cmd(cp,
- (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),NULL);
-}
-
-
-void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
-{
- int stat;
- struct pvr2_hdw *hdw = cp->hdw;
- if (hdw->cropcap_stale) {
- hdw->cropcap_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP,
- &hdw->cropcap_info);
- if (stat == 0) {
- /* Check was successful, so the data is no
- longer considered stale. */
- hdw->cropcap_stale = 0;
- }
- }
- pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info);
-}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
deleted file mode 100644
index 69a63f2a8..000000000
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
- * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * 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
- *
- * 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 __PVRUSB2_CMD_V4L2_H
-#define __PVRUSB2_CMD_V4L2_H
-
-#include "pvrusb2-i2c-core.h"
-
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_init;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
-
-void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
-void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
-
-#endif /* __PVRUSB2_CMD_V4L2_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index d95abcc55..fde4d3bd1 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -18,6 +18,7 @@
*
*/
+#include <linux/i2c.h>
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
@@ -30,8 +31,7 @@
/*
This module attempts to implement a compliant I2C adapter for the pvrusb2
- device. By doing this we can then make use of existing functionality in
- V4L (e.g. tuner.c) rather than rolling our own.
+ device.
*/
@@ -43,10 +43,6 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
module_param_array(ir_mode, int, NULL, 0444);
MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
- unsigned int detail,
- char *buf,unsigned int maxlen);
-
static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
u8 i2c_addr, /* I2C address we're talking to */
u8 *data, /* Data to write */
@@ -599,414 +595,13 @@ static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
}
-static int pvr2_i2c_core_singleton(struct i2c_client *cp,
- unsigned int cmd,void *arg)
-{
- int stat;
- if (!cp) return -EINVAL;
- if (!(cp->driver)) return -EINVAL;
- if (!(cp->driver->command)) return -EINVAL;
- if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
- stat = cp->driver->command(cp,cmd,arg);
- module_put(cp->driver->driver.owner);
- return stat;
-}
-
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
-{
- int stat;
- if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
- char buf[100];
- unsigned int cnt;
- cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
- buf,sizeof(buf));
- pvr2_trace(PVR2_TRACE_I2C_CMD,
- "i2c COMMAND (code=%u 0x%x) to %.*s",
- cmd,cmd,cnt,buf);
- }
- stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
- if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
- char buf[100];
- unsigned int cnt;
- cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
- buf,sizeof(buf));
- pvr2_trace(PVR2_TRACE_I2C_CMD,
- "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
- }
- return stat;
-}
-
-int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
-{
- struct pvr2_i2c_client *cp, *ncp;
- int stat = -EINVAL;
-
- if (!hdw) return stat;
-
- mutex_lock(&hdw->i2c_list_lock);
- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
- if (!cp->recv_enable) continue;
- mutex_unlock(&hdw->i2c_list_lock);
- stat = pvr2_i2c_client_cmd(cp,cmd,arg);
- mutex_lock(&hdw->i2c_list_lock);
- }
- mutex_unlock(&hdw->i2c_list_lock);
- return stat;
-}
-
-
-static int handler_check(struct pvr2_i2c_client *cp)
-{
- struct pvr2_i2c_handler *hp = cp->handler;
- if (!hp) return 0;
- if (!hp->func_table->check) return 0;
- return hp->func_table->check(hp->func_data) != 0;
-}
-
-#define BUFSIZE 500
-
-
-void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
-{
- struct pvr2_i2c_client *cp;
- mutex_lock(&hdw->i2c_list_lock); do {
- struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
- memset(vtp,0,sizeof(*vtp));
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- if (!cp->detected_flag) continue;
- if (!cp->status_poll) continue;
- cp->status_poll(cp);
- }
- hdw->tuner_signal_stale = 0;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
- " type=%u strength=%u audio=0x%x cap=0x%x"
- " low=%u hi=%u",
- vtp->type,
- vtp->signal,vtp->rxsubchans,vtp->capability,
- vtp->rangelow,vtp->rangehigh);
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-
-/* Issue various I2C operations to bring chip-level drivers into sync with
- state stored in this driver. */
-void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
-{
- unsigned long msk;
- unsigned int idx;
- struct pvr2_i2c_client *cp, *ncp;
-
- if (!hdw->i2c_linked) return;
- if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
- return;
- }
- mutex_lock(&hdw->i2c_list_lock); do {
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
- /* One or more I2C clients have attached since we
- last synced. So scan the list and identify the
- new clients. */
- char *buf;
- unsigned int cnt;
- unsigned long amask = 0;
- buf = kmalloc(BUFSIZE,GFP_KERNEL);
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- if (!cp->detected_flag) {
- cp->ctl_mask = 0;
- pvr2_i2c_probe(hdw,cp);
- cp->detected_flag = !0;
- msk = cp->ctl_mask;
- cnt = 0;
- if (buf) {
- cnt = pvr2_i2c_client_describe(
- cp,
- PVR2_I2C_DETAIL_ALL,
- buf,BUFSIZE);
- }
- trace_i2c("Probed: %.*s",cnt,buf);
- if (handler_check(cp)) {
- hdw->i2c_pend_types |=
- PVR2_I2C_PEND_CLIENT;
- }
- cp->pend_mask = msk;
- hdw->i2c_pend_mask |= msk;
- hdw->i2c_pend_types |=
- PVR2_I2C_PEND_REFRESH;
- }
- amask |= cp->ctl_mask;
- }
- hdw->i2c_active_mask = amask;
- if (buf) kfree(buf);
- }
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
- /* Need to do one or more global updates. Arrange
- for this to happen. */
- unsigned long m2;
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: PEND_STALE (0x%lx)",
- hdw->i2c_stale_mask);
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- m2 = hdw->i2c_stale_mask;
- m2 &= cp->ctl_mask;
- m2 &= ~cp->pend_mask;
- if (m2) {
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: cp=%p setting 0x%lx",
- cp,m2);
- cp->pend_mask |= m2;
- }
- }
- hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
- hdw->i2c_stale_mask = 0;
- hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
- }
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
- /* One or more client handlers are asking for an
- update. Run through the list of known clients
- and update each one. */
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
- list) {
- if (!cp->handler) continue;
- if (!cp->handler->func_table->update) continue;
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: cp=%p update",cp);
- mutex_unlock(&hdw->i2c_list_lock);
- cp->handler->func_table->update(
- cp->handler->func_data);
- mutex_lock(&hdw->i2c_list_lock);
- /* If client's update function set some
- additional pending bits, account for that
- here. */
- if (cp->pend_mask & ~hdw->i2c_pend_mask) {
- hdw->i2c_pend_mask |= cp->pend_mask;
- hdw->i2c_pend_types |=
- PVR2_I2C_PEND_REFRESH;
- }
- }
- }
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
- const struct pvr2_i2c_op *opf;
- unsigned long pm;
- /* Some actual updates are pending. Walk through
- each update type and perform it. */
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
- " (0x%lx)",hdw->i2c_pend_mask);
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
- pm = hdw->i2c_pend_mask;
- hdw->i2c_pend_mask = 0;
- for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
- if (!(pm & msk)) continue;
- pm &= ~msk;
- list_for_each_entry(cp, &hdw->i2c_clients,
- list) {
- if (cp->pend_mask & msk) {
- cp->pend_mask &= ~msk;
- cp->recv_enable = !0;
- } else {
- cp->recv_enable = 0;
- }
- }
- opf = pvr2_i2c_get_op(idx);
- if (!opf) continue;
- mutex_unlock(&hdw->i2c_list_lock);
- opf->update(hdw);
- mutex_lock(&hdw->i2c_list_lock);
- }
- }
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
-{
- unsigned long msk,sm,pm;
- unsigned int idx;
- const struct pvr2_i2c_op *opf;
- struct pvr2_i2c_client *cp;
- unsigned int pt = 0;
-
- pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
-
- pm = hdw->i2c_active_mask;
- sm = 0;
- for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
- if (!(msk & pm)) continue;
- pm &= ~msk;
- opf = pvr2_i2c_get_op(idx);
- if (!(opf && opf->check)) continue;
- if (opf->check(hdw)) {
- sm |= msk;
- }
- }
- if (sm) pt |= PVR2_I2C_PEND_STALE;
-
- list_for_each_entry(cp, &hdw->i2c_clients, list)
- if (handler_check(cp))
- pt |= PVR2_I2C_PEND_CLIENT;
-
- if (pt) {
- mutex_lock(&hdw->i2c_list_lock); do {
- hdw->i2c_pend_types |= pt;
- hdw->i2c_stale_mask |= sm;
- hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- }
-
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: types=0x%x stale=0x%lx pend=0x%lx",
- hdw->i2c_pend_types,
- hdw->i2c_stale_mask,
- hdw->i2c_pend_mask);
- pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
-
- return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
-}
-
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
- unsigned int detail,
- char *buf,unsigned int maxlen)
-{
- unsigned int ccnt,bcnt;
- int spcfl = 0;
- const struct pvr2_i2c_op *opf;
-
- ccnt = 0;
- if (detail & PVR2_I2C_DETAIL_DEBUG) {
- bcnt = scnprintf(buf,maxlen,
- "ctxt=%p ctl_mask=0x%lx",
- cp,cp->ctl_mask);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- spcfl = !0;
- }
- bcnt = scnprintf(buf,maxlen,
- "%s%s @ 0x%x",
- (spcfl ? " " : ""),
- cp->client->name,
- cp->client->addr);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
- cp->handler && cp->handler->func_table->describe) {
- bcnt = scnprintf(buf,maxlen," (");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- bcnt = cp->handler->func_table->describe(
- cp->handler->func_data,buf,maxlen);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- bcnt = scnprintf(buf,maxlen,")");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
- unsigned int idx;
- unsigned long msk,sm;
-
- bcnt = scnprintf(buf,maxlen," [");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- sm = 0;
- spcfl = 0;
- for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
- if (!(cp->ctl_mask & msk)) continue;
- opf = pvr2_i2c_get_op(idx);
- if (opf) {
- bcnt = scnprintf(buf,maxlen,"%s%s",
- spcfl ? " " : "",
- opf->name);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- spcfl = !0;
- } else {
- sm |= msk;
- }
- }
- if (sm) {
- bcnt = scnprintf(buf,maxlen,"%s%lx",
- idx != 0 ? " " : "",sm);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- bcnt = scnprintf(buf,maxlen,"]");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- return ccnt;
-}
-
-unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
- char *buf,unsigned int maxlen)
-{
- unsigned int ccnt,bcnt;
- struct pvr2_i2c_client *cp;
- ccnt = 0;
- mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- bcnt = pvr2_i2c_client_describe(
- cp,
- (PVR2_I2C_DETAIL_HANDLER|
- PVR2_I2C_DETAIL_CTLMASK),
- buf,maxlen);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- bcnt = scnprintf(buf,maxlen,"\n");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- return ccnt;
-}
-
static int pvr2_i2c_attach_inform(struct i2c_client *client)
{
- struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
- struct pvr2_i2c_client *cp;
- int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
- cp = kzalloc(sizeof(*cp),GFP_KERNEL);
- trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
- client->name,
- client->addr,cp);
- if (!cp) return -ENOMEM;
- cp->hdw = hdw;
- INIT_LIST_HEAD(&cp->list);
- cp->client = client;
- mutex_lock(&hdw->i2c_list_lock); do {
- hdw->cropcap_stale = !0;
- list_add_tail(&cp->list,&hdw->i2c_clients);
- hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
return 0;
}
static int pvr2_i2c_detach_inform(struct i2c_client *client)
{
- struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
- struct pvr2_i2c_client *cp, *ncp;
- unsigned long amask = 0;
- int foundfl = 0;
- mutex_lock(&hdw->i2c_list_lock); do {
- hdw->cropcap_stale = !0;
- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
- if (cp->client == client) {
- trace_i2c("pvr2_i2c_detach"
- " [client=%s @ 0x%x ctxt=%p]",
- client->name,
- client->addr,cp);
- if (cp->handler &&
- cp->handler->func_table->detach) {
- cp->handler->func_table->detach(
- cp->handler->func_data);
- }
- list_del(&cp->list);
- kfree(cp);
- foundfl = !0;
- continue;
- }
- amask |= cp->ctl_mask;
- }
- hdw->i2c_active_mask = amask;
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- if (!foundfl) {
- trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
- client->name,
- client->addr);
- }
return 0;
}
@@ -1020,7 +615,7 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
static struct i2c_adapter pvr2_i2c_adap_template = {
.owner = THIS_MODULE,
- .class = I2C_CLASS_TV_ANALOG,
+ .class = 0,
.id = I2C_HW_B_BT848,
.client_register = pvr2_i2c_attach_inform,
.client_unregister = pvr2_i2c_detach_inform,
@@ -1087,12 +682,8 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
hdw->i2c_adap.algo = &hdw->i2c_algo;
hdw->i2c_adap.algo_data = hdw;
- hdw->i2c_pend_mask = 0;
- hdw->i2c_stale_mask = 0;
- hdw->i2c_active_mask = 0;
- INIT_LIST_HEAD(&hdw->i2c_clients);
- mutex_init(&hdw->i2c_list_lock);
hdw->i2c_linked = !0;
+ i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
i2c_add_adapter(&hdw->i2c_adap);
if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
/* Probe for a different type of IR receiver on this
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index 6ef7a1c0e..6a7576920 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -20,68 +20,13 @@
#ifndef __PVRUSB2_I2C_CORE_H
#define __PVRUSB2_I2C_CORE_H
-#include <linux/list.h>
-#include <linux/i2c.h>
-
struct pvr2_hdw;
-struct pvr2_i2c_client;
-struct pvr2_i2c_handler;
-struct pvr2_i2c_handler_functions;
-struct pvr2_i2c_op;
-struct pvr2_i2c_op_functions;
-
-struct pvr2_i2c_client {
- struct i2c_client *client;
- struct pvr2_i2c_handler *handler;
- struct list_head list;
- struct pvr2_hdw *hdw;
- int detected_flag;
- int recv_enable;
- unsigned long pend_mask;
- unsigned long ctl_mask;
- void (*status_poll)(struct pvr2_i2c_client *);
-};
-
-struct pvr2_i2c_handler {
- void *func_data;
- const struct pvr2_i2c_handler_functions *func_table;
-};
-
-struct pvr2_i2c_handler_functions {
- void (*detach)(void *);
- int (*check)(void *);
- void (*update)(void *);
- unsigned int (*describe)(void *,char *,unsigned int);
-};
-
-struct pvr2_i2c_op {
- int (*check)(struct pvr2_hdw *);
- void (*update)(struct pvr2_hdw *);
- const char *name;
-};
void pvr2_i2c_core_init(struct pvr2_hdw *);
void pvr2_i2c_core_done(struct pvr2_hdw *);
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
-int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
-
-int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
-void pvr2_i2c_core_sync(struct pvr2_hdw *);
-void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
-unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
-#define PVR2_I2C_DETAIL_DEBUG 0x0001
-#define PVR2_I2C_DETAIL_HANDLER 0x0002
-#define PVR2_I2C_DETAIL_CTLMASK 0x0004
-#define PVR2_I2C_DETAIL_ALL (\
- PVR2_I2C_DETAIL_DEBUG |\
- PVR2_I2C_DETAIL_HANDLER |\
- PVR2_I2C_DETAIL_CTLMASK)
-
-void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
-const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
-#endif /* __PVRUSB2_I2C_CORE_H */
+#endif /* __PVRUSB2_I2C_ADAPTER_H */
/*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
deleted file mode 100644
index efec78516..000000000
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
- * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * 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
- *
- * 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
- *
- */
-
-#include "pvrusb2.h"
-#include "pvrusb2-util.h"
-#include "pvrusb2-tuner.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-debug.h"
-#include "compat.h"
-#include <linux/videodev2.h>
-#include <media/tuner.h>
-#include <media/v4l2-common.h>
-
-struct pvr2_tuner_handler {
- struct pvr2_hdw *hdw;
- struct pvr2_i2c_client *client;
- struct pvr2_i2c_handler i2c_handler;
- int type_update_fl;
-};
-
-
-static void set_type(struct pvr2_tuner_handler *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- struct tuner_setup setup;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c tuner set_type(%d)",hdw->tuner_type);
- if (((int)(hdw->tuner_type)) < 0) return;
-
- setup.addr = ADDR_UNSET;
- setup.type = hdw->tuner_type;
- setup.mode_mask = T_RADIO | T_ANALOG_TV;
- /* We may really want mode_mask to be T_ANALOG_TV for now */
- pvr2_i2c_client_cmd(ctxt->client,TUNER_SET_TYPE_ADDR,&setup);
- ctxt->type_update_fl = 0;
-}
-
-
-static int tuner_check(struct pvr2_tuner_handler *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- if (hdw->tuner_updated) ctxt->type_update_fl = !0;
- return ctxt->type_update_fl != 0;
-}
-
-
-static void tuner_update(struct pvr2_tuner_handler *ctxt)
-{
- if (ctxt->type_update_fl) set_type(ctxt);
-}
-
-
-static void pvr2_tuner_detach(struct pvr2_tuner_handler *ctxt)
-{
- ctxt->client->handler = NULL;
- kfree(ctxt);
-}
-
-
-static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *buf,unsigned int cnt)
-{
- return scnprintf(buf,cnt,"handler: pvrusb2-tuner");
-}
-
-
-static const struct pvr2_i2c_handler_functions tuner_funcs = {
- .detach = (void (*)(void *))pvr2_tuner_detach,
- .check = (int (*)(void *))tuner_check,
- .update = (void (*)(void *))tuner_update,
- .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_tuner_describe,
-};
-
-
-int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
- struct pvr2_tuner_handler *ctxt;
- if (cp->handler) return 0;
-
- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
- if (!ctxt) return 0;
-
- ctxt->i2c_handler.func_data = ctxt;
- ctxt->i2c_handler.func_table = &tuner_funcs;
- ctxt->type_update_fl = !0;
- ctxt->client = cp;
- ctxt->hdw = hdw;
- cp->handler = &ctxt->i2c_handler;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tuner handler set up",
- cp->client->addr);
- return !0;
-}
-
-
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index e4bf0278c..c7fc605f8 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -953,10 +953,6 @@ static long pvr2_v4l2_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
-/* Temporary hack : use ivtv api until a v4l2 one is available. */
-#define IVTV_IOC_G_CODEC 0xFFEE7703
-#define IVTV_IOC_S_CODEC 0xFFEE7704
- if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index b1ff3803f..b29a42ef5 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -28,7 +28,7 @@
*/
#include "pvrusb2-video-v4l.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
+
#include "pvrusb2-hdw-internal.h"
@@ -40,15 +40,6 @@
#include <linux/slab.h>
#include "compat.h"
-struct pvr2_v4l_decoder {
- struct pvr2_i2c_handler handler;
- struct pvr2_decoder_ctrl ctrl;
- struct pvr2_i2c_client *client;
- struct pvr2_hdw *hdw;
- unsigned long stale_mask;
-};
-
-
struct routing_scheme {
const int *def;
unsigned int cnt;
@@ -64,190 +55,51 @@ static const int routing_scheme0[] = {
[PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2,
};
+static const int routing_scheme1[] = {
+ [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
+ [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
+ [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE3,
+ [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, /* or SVIDEO0, it seems */
+};
+
static const struct routing_scheme routing_schemes[] = {
[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
.def = routing_scheme0,
.cnt = ARRAY_SIZE(routing_scheme0),
},
+ [PVR2_ROUTING_SCHEME_ONAIR] = {
+ .def = routing_scheme1,
+ .cnt = ARRAY_SIZE(routing_scheme1),
+ },
};
-static void set_input(struct pvr2_v4l_decoder *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- struct v4l2_routing route;
- const struct routing_scheme *sp;
- unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
-
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
-
- if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != NULL) &&
- (hdw->input_val >= 0) &&
- (hdw->input_val < sp->cnt)) {
- route.input = sp->def[hdw->input_val];
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "*** WARNING *** i2c v4l2 set_input:"
- " Invalid routing scheme (%u) and/or input (%d)",
- sid,hdw->input_val);
- return;
- }
-
- route.output = 0;
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
-}
-
-
-static int check_input(struct pvr2_v4l_decoder *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->input_dirty != 0;
-}
-
-
-static void set_audio(struct pvr2_v4l_decoder *ctxt)
-{
- u32 val;
- struct pvr2_hdw *hdw = ctxt->hdw;
-
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d",
- hdw->srate_val);
- switch (hdw->srate_val) {
- default:
- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
- val = 48000;
- break;
- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
- val = 44100;
- break;
- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
- val = 32000;
- break;
- }
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
-}
-
-
-static int check_audio(struct pvr2_v4l_decoder *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->srate_dirty != 0;
-}
-
-
-struct pvr2_v4l_decoder_ops {
- void (*update)(struct pvr2_v4l_decoder *);
- int (*check)(struct pvr2_v4l_decoder *);
-};
-
-
-static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
- { .update = set_input, .check = check_input},
- { .update = set_audio, .check = check_audio},
-};
-
-
-static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
+void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
{
- ctxt->client->handler = NULL;
- pvr2_hdw_set_decoder(ctxt->hdw,NULL);
- kfree(ctxt);
-}
-
-
-static int decoder_check(struct pvr2_v4l_decoder *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
- msk = 1 << idx;
- if (ctxt->stale_mask & msk) continue;
- if (decoder_ops[idx].check(ctxt)) {
- ctxt->stale_mask |= msk;
+ if (hdw->input_dirty || hdw->force_dirty) {
+ struct v4l2_routing route;
+ const struct routing_scheme *sp;
+ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
+ hdw->input_val);
+ if ((sid < ARRAY_SIZE(routing_schemes)) &&
+ ((sp = routing_schemes + sid) != NULL) &&
+ (hdw->input_val >= 0) &&
+ (hdw->input_val < sp->cnt)) {
+ route.input = sp->def[hdw->input_val];
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "*** WARNING *** subdev v4l2 set_input:"
+ " Invalid routing scheme (%u)"
+ " and/or input (%d)",
+ sid, hdw->input_val);
+ return;
}
+ route.output = 0;
+ sd->ops->video->s_routing(sd, &route);
}
- return ctxt->stale_mask != 0;
-}
-
-
-static void decoder_update(struct pvr2_v4l_decoder *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
- msk = 1 << idx;
- if (!(ctxt->stale_mask & msk)) continue;
- ctxt->stale_mask &= ~msk;
- decoder_ops[idx].update(ctxt);
- }
-}
-
-
-static int decoder_detect(struct pvr2_i2c_client *cp)
-{
- /* Attempt to query the decoder - let's see if it will answer */
- struct v4l2_tuner vt;
- int ret;
-
- memset(&vt,0,sizeof(vt));
- ret = pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&vt);
- return ret == 0; /* Return true if it answered */
-}
-
-
-static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
-{
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl);
- pvr2_v4l2_cmd_stream(ctxt->client,fl);
-}
-
-
-static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
-{
- return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
-}
-
-
-static const struct pvr2_i2c_handler_functions hfuncs = {
- .detach = (void (*)(void *))decoder_detach,
- .check = (int (*)(void *))decoder_check,
- .update = (void (*)(void *))decoder_update,
- .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
-};
-
-
-int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
- struct pvr2_i2c_client *cp)
-{
- struct pvr2_v4l_decoder *ctxt;
-
- if (hdw->decoder_ctrl) return 0;
- if (cp->handler) return 0;
- if (!decoder_detect(cp)) return 0;
-
- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
- if (!ctxt) return 0;
-
- ctxt->handler.func_data = ctxt;
- ctxt->handler.func_table = &hfuncs;
- ctxt->ctrl.ctxt = ctxt;
- ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
- ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->client = cp;
- ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
- pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
- cp->handler = &ctxt->handler;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
- cp->client->addr);
- return !0;
}
-
-
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
index 4ff5b892b..3b0bd5db6 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
@@ -32,11 +32,8 @@
*/
-
-#include "pvrusb2-i2c-core.h"
-
-int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
-
+#include "pvrusb2-hdw-internal.h"
+void pvr2_saa7115_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
#endif /* __PVRUSB2_VIDEO_V4L_H */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
index 6cdcbf2fe..6364434a5 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -27,7 +27,6 @@
*/
#include "pvrusb2-wm8775.h"
-#include "pvrusb2-i2c-cmd-v4l2.h"
#include "pvrusb2-hdw-internal.h"
@@ -38,128 +37,31 @@
#include <linux/slab.h>
#include "compat.h"
-struct pvr2_v4l_wm8775 {
- struct pvr2_i2c_handler handler;
- struct pvr2_i2c_client *client;
- struct pvr2_hdw *hdw;
- unsigned long stale_mask;
-};
-
-
-static void set_input(struct pvr2_v4l_wm8775 *ctxt)
-{
- struct v4l2_routing route;
- struct pvr2_hdw *hdw = ctxt->hdw;
-
- memset(&route,0,sizeof(route));
-
- switch(hdw->input_val) {
- case PVR2_CVAL_INPUT_RADIO:
- route.input = 1;
- break;
- default:
- /* All other cases just use the second input */
- route.input = 2;
- break;
- }
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d route=0x%x)",
- hdw->input_val,route.input);
-
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
-}
-
-static int check_input(struct pvr2_v4l_wm8775 *ctxt)
-{
- struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->input_dirty != 0;
-}
-
-
-struct pvr2_v4l_wm8775_ops {
- void (*update)(struct pvr2_v4l_wm8775 *);
- int (*check)(struct pvr2_v4l_wm8775 *);
-};
-
-
-static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = {
- { .update = set_input, .check = check_input},
-};
-
-
-static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt,
- char *buf,unsigned int cnt)
-{
- return scnprintf(buf,cnt,"handler: pvrusb2-wm8775");
-}
-
-
-static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt)
+void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
{
- ctxt->client->handler = NULL;
- kfree(ctxt);
-}
-
-
-static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
- msk = 1 << idx;
- if (ctxt->stale_mask & msk) continue;
- if (wm8775_ops[idx].check(ctxt)) {
- ctxt->stale_mask |= msk;
+ if (hdw->input_dirty || hdw->force_dirty) {
+ struct v4l2_routing route;
+
+ memset(&route, 0, sizeof(route));
+
+ switch (hdw->input_val) {
+ case PVR2_CVAL_INPUT_RADIO:
+ route.input = 1;
+ break;
+ default:
+ /* All other cases just use the second input */
+ route.input = 2;
+ break;
}
- }
- return ctxt->stale_mask != 0;
-}
-
-
-static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
-{
- unsigned long msk;
- unsigned int idx;
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev wm8775"
+ " set_input(val=%d route=0x%x)",
+ hdw->input_val, route.input);
- for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
- msk = 1 << idx;
- if (!(ctxt->stale_mask & msk)) continue;
- ctxt->stale_mask &= ~msk;
- wm8775_ops[idx].update(ctxt);
+ sd->ops->audio->s_routing(sd, &route);
}
}
-static const struct pvr2_i2c_handler_functions hfuncs = {
- .detach = (void (*)(void *))wm8775_detach,
- .check = (int (*)(void *))wm8775_check,
- .update = (void (*)(void *))wm8775_update,
- .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe,
-};
-
-
-int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
-{
- struct pvr2_v4l_wm8775 *ctxt;
-
- if (cp->handler) return 0;
-
- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
- if (!ctxt) return 0;
-
- ctxt->handler.func_data = ctxt;
- ctxt->handler.func_table = &hfuncs;
- ctxt->client = cp;
- ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
- cp->handler = &ctxt->handler;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
- cp->client->addr);
- return !0;
-}
-
-
-
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
index 807090961..0577bc724 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
@@ -34,9 +34,9 @@
-#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
-int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+void pvr2_wm8775_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
#endif /* __PVRUSB2_WM8775_H */
diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c
index 49a918636..b3765e280 100644
--- a/linux/drivers/media/video/pwc/pwc-if.c
+++ b/linux/drivers/media/video/pwc/pwc-if.c
@@ -1133,6 +1133,7 @@ static int pwc_video_open(struct file *file)
}
mutex_lock(&pdev->modlock);
+ pwc_construct(pdev); /* set min/max sizes correct */
if (!pdev->usb_init) {
PWC_DEBUG_OPEN("Doing first time initialization.\n");
pdev->usb_init = 1;
@@ -1157,7 +1158,6 @@ static int pwc_video_open(struct file *file)
if (pwc_set_leds(pdev, led_on, led_off) < 0)
PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
- pwc_construct(pdev); /* set min/max sizes correct */
/* So far, so good. Allocate memory. */
i = pwc_allocate_buffers(pdev);
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index dd524b3c6..d1aa540ba 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -1160,8 +1160,43 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
return formats;
}
+static int pxa_camera_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ struct soc_camera_sense sense = {
+ .master_clock = pcdev->mclk,
+ .pixel_clock_max = pcdev->ciclk / 4,
+ };
+ 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);
+
+ icd->sense = NULL;
+
+ if (ret < 0) {
+ dev_warn(&ici->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) {
+ if (sense.pixel_clock > sense.pixel_clock_max) {
+ dev_err(&ici->dev,
+ "pixel clock %lu set by the camera too high!",
+ sense.pixel_clock);
+ return -EIO;
+ }
+ recalculate_fifo_timeout(pcdev, sense.pixel_clock);
+ }
+
+ return ret;
+}
+
static int pxa_camera_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+ struct v4l2_format *f)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
@@ -1171,35 +1206,30 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
.master_clock = pcdev->mclk,
.pixel_clock_max = pcdev->ciclk / 4,
};
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_format cam_f = *f;
int ret;
- if (pixfmt) {
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- if (!xlate) {
- dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
- return -EINVAL;
- }
-
- cam_fmt = xlate->cam_fmt;
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+ return -EINVAL;
}
+ cam_fmt = xlate->cam_fmt;
+
/* If PCLK is used to latch data from the sensor, check sense */
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
icd->sense = &sense;
- switch (pixfmt) {
- case 0: /* Only geometry change */
- ret = icd->ops->set_fmt(icd, pixfmt, rect);
- break;
- default:
- ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
- }
+ cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
+ ret = icd->ops->set_fmt(icd, &cam_f);
icd->sense = NULL;
if (ret < 0) {
dev_warn(&ici->dev, "Failed to configure for format %x\n",
- pixfmt);
+ pix->pixelformat);
} else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
if (sense.pixel_clock > sense.pixel_clock_max) {
dev_err(&ici->dev,
@@ -1210,7 +1240,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
recalculate_fifo_timeout(pcdev, sense.pixel_clock);
}
- if (pixfmt && !ret) {
+ if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
}
@@ -1374,6 +1404,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.remove = pxa_camera_remove_device,
.suspend = pxa_camera_suspend,
.resume = pxa_camera_resume,
+ .set_crop = pxa_camera_set_crop,
.get_formats = pxa_camera_get_formats,
.set_fmt = pxa_camera_set_fmt,
.try_fmt = pxa_camera_try_fmt,
diff --git a/linux/drivers/media/video/saa6588.c b/linux/drivers/media/video/saa6588.c
index ae96de5fd..d89d70892 100644
--- a/linux/drivers/media/video/saa6588.c
+++ b/linux/drivers/media/video/saa6588.c
@@ -77,8 +77,7 @@ MODULE_LICENSE("GPL");
struct saa6588 {
struct v4l2_subdev sd;
- struct work_struct work;
- struct timer_list timer;
+ struct delayed_work work;
spinlock_t lock;
unsigned char *buffer;
unsigned int buf_size;
@@ -323,13 +322,6 @@ static void saa6588_i2c_poll(struct saa6588 *s)
wake_up_interruptible(&s->read_queue);
}
-static void saa6588_timer(unsigned long data)
-{
- struct saa6588 *s = (struct saa6588 *)data;
-
- schedule_work(&s->work);
-}
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
static void saa6588_work(void *data)
#else
@@ -339,11 +331,11 @@ static void saa6588_work(struct work_struct *work)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
struct saa6588 *s = (struct saa6588 *)data;
#else
- struct saa6588 *s = container_of(work, struct saa6588, work);
+ struct saa6588 *s = container_of(work, struct saa6588, work.work);
#endif
saa6588_i2c_poll(s);
- mod_timer(&s->timer, jiffies + msecs_to_jiffies(20));
+ schedule_delayed_work(&s->work, msecs_to_jiffies(20));
}
static int saa6588_configure(struct saa6588 *s)
@@ -500,14 +492,11 @@ static int saa6588_probe(struct i2c_client *client,
/* start polling via eventd */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
- INIT_WORK(&s->work, saa6588_work, s);
+ INIT_DELAYED_WORK(&s->work, saa6588_work, s);
#else
- INIT_WORK(&s->work, saa6588_work);
+ INIT_DELAYED_WORK(&s->work, saa6588_work);
#endif
- init_timer(&s->timer);
- s->timer.function = saa6588_timer;
- s->timer.data = (unsigned long)s;
- schedule_work(&s->work);
+ schedule_delayed_work(&s->work, 0);
return 0;
}
@@ -518,8 +507,7 @@ static int saa6588_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
- del_timer_sync(&s->timer);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&s->work);
kfree(s->buffer);
kfree(s);
diff --git a/linux/drivers/media/video/saa7110.c b/linux/drivers/media/video/saa7110.c
index ad21fdec1..bb58477e5 100644
--- a/linux/drivers/media/video/saa7110.c
+++ b/linux/drivers/media/video/saa7110.c
@@ -257,7 +257,7 @@ static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
int status = saa7110_read(sd);
v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
- status, decoder->norm);
+ status, (unsigned long long)decoder->norm);
if (!(status & 0x40))
res = 0;
if (!(status & 0x03))
diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig
index fc2164e28..a2089acb0 100644
--- a/linux/drivers/media/video/saa7134/Kconfig
+++ b/linux/drivers/media/video/saa7134/Kconfig
@@ -35,8 +35,16 @@ config VIDEO_SAA7134_DVB
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+ select DVB_ISL6405 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+ select DVB_ZL10036 if !DVB_FE_CUSTOMISE
+ select DVB_MT312 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c
index 3af36d929..2b82466d4 100644
--- a/linux/drivers/media/video/saa7134/saa6752hs.c
+++ b/linux/drivers/media/video/saa7134/saa6752hs.c
@@ -48,7 +48,7 @@
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
/* Addresses to scan */
-static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
+static unsigned short normal_i2c[] = {0x20, 0x21, I2C_CLIENT_END};
I2C_CLIENT_INSMOD;
#endif
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index 9db045cf5..50d2868ce 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -31,6 +31,7 @@
#include <media/v4l2-common.h>
#include <media/tveeprom.h>
#include "tea5767.h"
+#include "tda18271.h"
/* commly used strings */
static char name_mute[] = "mute";
@@ -272,6 +273,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
.inputs = {{
.name = name_comp1,
@@ -408,6 +410,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x820000,
.inputs = {{
@@ -818,6 +821,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
.inputs = {{
.name = name_comp1,
.vmux = 4,
@@ -977,6 +981,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
.inputs = {{
.name = name_comp1,
.vmux = 1,
@@ -2364,6 +2369,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x21,
.inputs = {{
.name = "Composite 0",
.vmux = 0,
@@ -3330,6 +3336,68 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x0200100,
},
},
+ [SAA7134_BOARD_HAUPPAUGE_HVR1120] = {
+ .name = "Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 3,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_SERIAL,
+ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x0000100,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0800100, /* GPIO 23 HI for FM */
+ },
+ },
+ [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = {
+ .name = "Hauppauge WinTV-HVR1110r3",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 3,
+ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x0000100,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0800100, /* GPIO 23 HI for FM */
+ },
+ },
[SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
.name = "Terratec Cinergy HT PCMCIA",
.audio_clock = 0x00187de7,
@@ -4109,6 +4177,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
.name = name_tv,
@@ -4145,6 +4214,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
.name = name_tv,
@@ -4182,6 +4252,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
.name = name_tv,
@@ -4460,8 +4531,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- /* no DVB support for now */
- /* .mpeg = SAA7134_MPEG_DVB, */
+ .mpeg = SAA7134_MPEG_DVB,
.inputs = { {
.name = name_comp,
.vmux = 1,
@@ -4480,8 +4550,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- /* no DVB support for now */
- /* .mpeg = SAA7134_MPEG_DVB, */
+ .mpeg = SAA7134_MPEG_DVB,
.inputs = { {
.name = name_comp,
.vmux = 1,
@@ -5444,6 +5513,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6706,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6707,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6708,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6709,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x670a,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x153b,
.subdevice = 0x1172,
.driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA,
@@ -5916,8 +6015,8 @@ static int saa7134_xc5000_callback(struct saa7134_dev *dev,
}
#endif
-static int saa7134_tda8290_callback(struct saa7134_dev *dev,
- int command, int arg)
+static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
+ int command, int arg)
{
u8 sync_control;
@@ -5943,6 +6042,65 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
return 0;
}
+static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ /* toggle AGC switch through GPIO 26 */
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa7134_set_gpio(dev, 26, 0);
+ break;
+ case TDA18271_DIGITAL:
+ saa7134_set_gpio(dev, 26, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ int ret = 0;
+
+ switch (command) {
+ case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */
+ switch (dev->board) {
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ int ret;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ /* tda8290 + tda18271 */
+ ret = saa7134_tda8290_18271_callback(dev, command, arg);
+ break;
+ default:
+ /* tda8290 + tda827x */
+ ret = saa7134_tda8290_827x_callback(dev, command, arg);
+ break;
+ }
+ return ret;
+}
+
int saa7134_tuner_callback(void *priv, int component, int command, int arg)
{
struct saa7134_dev *dev = priv;
@@ -5977,11 +6135,16 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
switch (tv.model) {
case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+ case 67201: /* WinTV-HVR1120 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+ case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+ case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+ case 67651: /* WinTV-HVR1120 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+ case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
break;
default:
printk(KERN_WARNING "%s: warning: "
@@ -6162,6 +6325,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ /* GPIO 26 high for digital, low for analog */
+ saa7134_set_gpio(dev, 26, 0);
+ msleep(1);
+
+ saa7134_set_gpio(dev, 22, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 22, 1);
+ break;
/* i2c remotes */
case SAA7134_BOARD_PINNACLE_PCTV_110i:
case SAA7134_BOARD_PINNACLE_PCTV_310i:
@@ -6187,15 +6360,15 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
break;
- case SAA7134_BOARD_AVERMEDIA_A700_PRO:
case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
- /* write windows gpio values */
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
printk("%s: %s: hybrid analog/dvb card\n"
- "%s: Sorry, only analog s-video and composite input "
+ "%s: Sorry, of the analog inputs, only analog s-video and composite "
"are supported for now.\n",
dev->name, card(dev).name, dev->name);
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ /* write windows gpio values */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
break;
}
return 0;
@@ -6414,6 +6587,10 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->name, saa7134_boards[dev->board].name);
}
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ hauppauge_eeprom(dev, dev->eedata+0x80);
+ break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
hauppauge_eeprom(dev, dev->eedata+0x80);
/* break intentionally omitted */
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index d499064ee..71142b53e 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -837,7 +837,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
return NULL;
*vfd = *template;
vfd->minor = -1;
- vfd->parent = &dev->pci->dev;
+ vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
@@ -1043,8 +1043,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* load i2c helpers */
if (card_is_empress(dev)) {
struct v4l2_subdev *sd =
- v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs",
- "saa6752hs", 0x20);
+ v4l2_i2c_new_subdev(&dev->i2c_adap,
+ "saa6752hs", "saa6752hs",
+ saa7134_boards[dev->board].empress_addr);
if (sd)
sd->grp_id = GRP_EMPRESS;
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index 27a4d9c83..2e1344ecf 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -48,9 +48,15 @@
#include "isl6405.h"
#include "lnbp21.h"
#include "tuner-simple.h"
+#include "tda18271.h"
+#include "lgdt3305.h"
+#include "tda8290.h"
#include "zl10353.h"
+#include "zl10036.h"
+#include "mt312.h"
+
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -860,6 +866,7 @@ static struct zl10353_config behold_h6_config = {
.demod_address = 0x1e>>1,
.no_tuner = 1,
.parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
};
/* ==================================================================
@@ -949,6 +956,45 @@ static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
};
+/* ------------------------------------------------------------------ */
+
+static struct mt312_config avertv_a700_mt312 = {
+ .demod_address = 0x0e,
+ .voltage_inverted = 1,
+};
+
+static struct zl10036_config avertv_a700_tuner = {
+ .tuner_address = 0x60,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+ .i2c_addr = 0x0e,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 1,
+ .qam_if_khz = 4000,
+ .vsb_if_khz = 3250,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .config = 3,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+ .probe_tuner = TDA829X_DONT_PROBE,
+};
+
/* ==================================================================
* Core code
*/
@@ -1075,6 +1121,19 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_1) < 0)
goto dettach_frontend;
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+ &hcw_lgdt3305_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &hcw_tda18271_config);
+ }
+ break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
&tda827x_cfg_0) < 0)
@@ -1379,6 +1438,19 @@ static int dvb_init(struct saa7134_dev *dev)
TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ /* Zarlink ZL10313 */
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &avertv_a700_mt312, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
+ &avertv_a700_tuner, &dev->i2c_adap) == NULL) {
+ wprintk("%s: No zl10036 found!\n",
+ __func__);
+ }
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index 609342128..bab6b56c8 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -416,8 +416,7 @@ static int empress_g_chip_ident(struct file *file, void *fh,
if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER &&
!strcmp(chip->match.name, "saa6752hs"))
return saa_call_empress(dev, core, g_chip_ident, chip);
- if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR &&
- chip->match.addr == 0x20)
+ if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR)
return saa_call_empress(dev, core, g_chip_ident, chip);
return -EINVAL;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-ts.c b/linux/drivers/media/video/saa7134/saa7134-ts.c
index ef55a59f0..cc8b923af 100644
--- a/linux/drivers/media/video/saa7134/saa7134-ts.c
+++ b/linux/drivers/media/video/saa7134/saa7134-ts.c
@@ -79,8 +79,19 @@ static int buffer_activate(struct saa7134_dev *dev,
saa_writeb(SAA7134_TS_SERIAL1, 0x00);
/* Start TS stream */
- saa_writeb(SAA7134_TS_SERIAL0, 0x40);
- saa_writeb(SAA7134_TS_PARALLEL, 0xEC);
+ switch (saa7134_boards[dev->board].ts_type) {
+ case SAA7134_MPEG_TS_PARALLEL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+ saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+ break;
+ case SAA7134_MPEG_TS_SERIAL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
+ saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x02);
+ break;
+ }
+
dev->ts_state = SAA7134_TS_STARTED;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c
index be7f98bc0..d188aae14 100644
--- a/linux/drivers/media/video/saa7134/saa7134-video.c
+++ b/linux/drivers/media/video/saa7134/saa7134-video.c
@@ -31,11 +31,6 @@
#include "saa7134.h"
#include <media/v4l2-common.h>
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
-
/* ------------------------------------------------------------------ */
unsigned int video_debug;
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index c9d4d4354..2e9c7ed3d 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -279,6 +279,8 @@ struct saa7134_format {
#define SAA7134_BOARD_ASUSTeK_TIGER 152
#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
+#define SAA7134_BOARD_HAUPPAUGE_HVR1120 155
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -311,6 +313,11 @@ enum saa7134_mpeg_type {
SAA7134_MPEG_DVB,
};
+enum saa7134_mpeg_ts_type {
+ SAA7134_MPEG_TS_PARALLEL = 0,
+ SAA7134_MPEG_TS_SERIAL,
+};
+
struct saa7134_board {
char *name;
unsigned int audio_clock;
@@ -326,6 +333,7 @@ struct saa7134_board {
unsigned int radio_type;
unsigned char tuner_addr;
unsigned char radio_addr;
+ unsigned char empress_addr;
unsigned int tda9887_conf;
unsigned int tuner_config;
@@ -333,6 +341,7 @@ struct saa7134_board {
/* peripheral I/O */
enum saa7134_video_out video_out;
enum saa7134_mpeg_type mpeg;
+ enum saa7134_mpeg_ts_type ts_type;
unsigned int vid_port_opts;
};
diff --git a/linux/drivers/media/video/saa7146.h b/linux/drivers/media/video/saa7146.h
index 2830b5e33..9fadb331a 100644
--- a/linux/drivers/media/video/saa7146.h
+++ b/linux/drivers/media/video/saa7146.h
@@ -25,8 +25,6 @@
#include <linux/types.h>
#include <linux/wait.h>
-#include <linux/videodev.h>
-
#ifndef O_NONCAP
#define O_NONCAP O_TRUNC
#endif
diff --git a/linux/drivers/media/video/saa7191.c b/linux/drivers/media/video/saa7191.c
index c4f169c95..9df505e0f 100644
--- a/linux/drivers/media/video/saa7191.c
+++ b/linux/drivers/media/video/saa7191.c
@@ -19,9 +19,11 @@
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
#include "compat.h"
#include "saa7191.h"
@@ -33,6 +35,12 @@ MODULE_VERSION(SAA7191_MODULE_VERSION);
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = { 0x8a >> 1, 0x8e >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+#endif
+
// #define SAA7191_DEBUG
#ifdef SAA7191_DEBUG
@@ -45,17 +53,20 @@ MODULE_LICENSE("GPL");
#define SAA7191_SYNC_DELAY 100 /* milliseconds */
struct saa7191 {
- struct i2c_client *client;
+ struct v4l2_subdev sd;
/* the register values are stored here as the actual
* I2C-registers are write-only */
u8 reg[25];
int input;
- int norm;
+ v4l2_std_id norm;
};
-static struct i2c_driver i2c_driver_saa7191;
+static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa7191, sd);
+}
static const u8 initseq[] = {
0, /* Subaddress */
@@ -101,15 +112,14 @@ static const u8 initseq[] = {
/* SAA7191 register handling */
-static u8 saa7191_read_reg(struct i2c_client *client,
- u8 reg)
+static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg)
{
- return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
+ return to_saa7191(sd)->reg[reg];
}
-static int saa7191_read_status(struct i2c_client *client,
- u8 *value)
+static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
ret = i2c_master_recv(client, value, 1);
@@ -122,21 +132,23 @@ static int saa7191_read_status(struct i2c_client *client,
}
-static int saa7191_write_reg(struct i2c_client *client, u8 reg,
- u8 value)
+static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
{
- ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ to_saa7191(sd)->reg[reg] = value;
return i2c_smbus_write_byte_data(client, reg, value);
}
/* the first byte of data must be the first subaddress number (register) */
-static int saa7191_write_block(struct i2c_client *client,
+static int saa7191_write_block(struct v4l2_subdev *sd,
u8 length, const u8 *data)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct saa7191 *decoder = to_saa7191(sd);
int i;
int ret;
- struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
for (i = 0; i < (length - 1); i++) {
decoder->reg[data[0] + i] = data[i + 1];
}
@@ -153,14 +165,15 @@ static int saa7191_write_block(struct i2c_client *client,
/* Helper functions */
-static int saa7191_set_input(struct i2c_client *client, int input)
+static int saa7191_s_routing(struct v4l2_subdev *sd,
+ const struct v4l2_routing *route)
{
- struct saa7191 *decoder = i2c_get_clientdata(client);
- u8 luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
- u8 iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
+ struct saa7191 *decoder = to_saa7191(sd);
+ u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+ u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK);
int err;
- switch (input) {
+ switch (route->input) {
case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
| SAA7191_IOCK_GPSW2);
@@ -176,54 +189,50 @@ static int saa7191_set_input(struct i2c_client *client, int input)
return -EINVAL;
}
- err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
+ err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma);
if (err)
return -EIO;
- err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
+ err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock);
if (err)
return -EIO;
- decoder->input = input;
+ decoder->input = route->input;
return 0;
}
-static int saa7191_set_norm(struct i2c_client *client, int norm)
+static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
{
- struct saa7191 *decoder = i2c_get_clientdata(client);
- u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
- u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
- u8 chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
+ struct saa7191 *decoder = to_saa7191(sd);
+ u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+ u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+ u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV);
int err;
- switch(norm) {
- case SAA7191_NORM_PAL:
+ if (norm & V4L2_STD_PAL) {
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
chcv = SAA7191_CHCV_PAL;
- break;
- case SAA7191_NORM_NTSC:
+ } else if (norm & V4L2_STD_NTSC) {
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~SAA7191_CTL3_AUFD;
ctl3 |= SAA7191_CTL3_FSEL;
chcv = SAA7191_CHCV_NTSC;
- break;
- case SAA7191_NORM_SECAM:
+ } else if (norm & V4L2_STD_SECAM) {
stdc |= SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
chcv = SAA7191_CHCV_PAL;
- break;
- default:
+ } else {
return -EINVAL;
}
- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
if (err)
return -EIO;
- err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
if (err)
return -EIO;
- err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
+ err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv);
if (err)
return -EIO;
@@ -231,19 +240,19 @@ static int saa7191_set_norm(struct i2c_client *client, int norm)
dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3,
stdc, chcv);
- dprintk("norm: %d\n", norm);
+ dprintk("norm: %llx\n", norm);
return 0;
}
-static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
+static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status)
{
int i = 0;
dprintk("Checking for signal...\n");
for (i = 0; i < SAA7191_SYNC_COUNT; i++) {
- if (saa7191_read_status(client, status))
+ if (saa7191_read_status(sd, status))
return -EIO;
if (((*status) & SAA7191_STATUS_HLCK) == 0) {
@@ -259,31 +268,34 @@ static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
return -EBUSY;
}
-static int saa7191_autodetect_norm_extended(struct i2c_client *client)
+static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
{
- u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
- u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ struct saa7191 *decoder = to_saa7191(sd);
+ u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+ u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
u8 status;
+ v4l2_std_id old_norm = decoder->norm;
int err = 0;
dprintk("SAA7191 extended signal auto-detection...\n");
+ *norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_FSEL);
- err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
if (err) {
err = -EIO;
goto out;
}
- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
if (err) {
err = -EIO;
goto out;
}
ctl3 |= SAA7191_CTL3_AUFD;
- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
if (err) {
err = -EIO;
goto out;
@@ -291,53 +303,54 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
msleep(SAA7191_SYNC_DELAY);
- err = saa7191_wait_for_signal(client, &status);
+ err = saa7191_wait_for_signal(sd, &status);
if (err)
goto out;
if (status & SAA7191_STATUS_FIDT) {
/* 60Hz signal -> NTSC */
dprintk("60Hz signal: NTSC\n");
- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+ *norm = V4L2_STD_NTSC;
+ return 0;
}
/* 50Hz signal */
dprintk("50Hz signal: Trying PAL...\n");
/* try PAL first */
- err = saa7191_set_norm(client, SAA7191_NORM_PAL);
+ err = saa7191_s_std(sd, V4L2_STD_PAL);
if (err)
goto out;
msleep(SAA7191_SYNC_DELAY);
- err = saa7191_wait_for_signal(client, &status);
+ err = saa7191_wait_for_signal(sd, &status);
if (err)
goto out;
/* not 50Hz ? */
if (status & SAA7191_STATUS_FIDT) {
dprintk("No 50Hz signal\n");
- err = -EAGAIN;
- goto out;
+ saa7191_s_std(sd, old_norm);
+ return -EAGAIN;
}
if (status & SAA7191_STATUS_CODE) {
dprintk("PAL\n");
- return 0;
+ *norm = V4L2_STD_PAL;
+ return saa7191_s_std(sd, old_norm);
}
dprintk("No color detected with PAL - Trying SECAM...\n");
/* no color detected ? -> try SECAM */
- err = saa7191_set_norm(client,
- SAA7191_NORM_SECAM);
+ err = saa7191_s_std(sd, V4L2_STD_SECAM);
if (err)
goto out;
msleep(SAA7191_SYNC_DELAY);
- err = saa7191_wait_for_signal(client, &status);
+ err = saa7191_wait_for_signal(sd, &status);
if (err)
goto out;
@@ -351,32 +364,17 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
if (status & SAA7191_STATUS_CODE) {
/* Color detected -> SECAM */
dprintk("SECAM\n");
- return 0;
+ *norm = V4L2_STD_SECAM;
+ return saa7191_s_std(sd, old_norm);
}
dprintk("No color detected with SECAM - Going back to PAL.\n");
- /* still no color detected ?
- * -> set norm back to PAL */
- err = saa7191_set_norm(client,
- SAA7191_NORM_PAL);
- if (err)
- goto out;
-
out:
- ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
- if (ctl3 & SAA7191_CTL3_AUFD) {
- ctl3 &= ~(SAA7191_CTL3_AUFD);
- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
- if (err) {
- err = -EIO;
- }
- }
-
- return err;
+ return saa7191_s_std(sd, old_norm);
}
-static int saa7191_autodetect_norm(struct i2c_client *client)
+static int saa7191_autodetect_norm(struct v4l2_subdev *sd)
{
u8 status;
@@ -384,7 +382,7 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
dprintk("Reading status...\n");
- if (saa7191_read_status(client, &status))
+ if (saa7191_read_status(sd, &status))
return -EIO;
dprintk("Checking for signal...\n");
@@ -400,26 +398,25 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
if (status & SAA7191_STATUS_FIDT) {
/* 60hz signal -> NTSC */
dprintk("NTSC\n");
- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+ return saa7191_s_std(sd, V4L2_STD_NTSC);
} else {
/* 50hz signal -> PAL */
dprintk("PAL\n");
- return saa7191_set_norm(client, SAA7191_NORM_PAL);
+ return saa7191_s_std(sd, V4L2_STD_PAL);
}
}
-static int saa7191_get_control(struct i2c_client *client,
- struct saa7191_control *ctrl)
+static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
u8 reg;
int ret = 0;
- switch (ctrl->type) {
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
case SAA7191_CONTROL_BANDPASS_WEIGHT:
case SAA7191_CONTROL_CORING:
- reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
- switch (ctrl->type) {
+ reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK)
>> SAA7191_LUMA_BPSS_SHIFT;
@@ -436,15 +433,15 @@ static int saa7191_get_control(struct i2c_client *client,
break;
case SAA7191_CONTROL_FORCE_COLOUR:
case SAA7191_CONTROL_CHROMA_GAIN:
- reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
- if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR)
+ reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+ if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR)
ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0;
else
ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK)
>> SAA7191_GAIN_LFIS_SHIFT;
break;
- case SAA7191_CONTROL_HUE:
- reg = saa7191_read_reg(client, SAA7191_REG_HUEC);
+ case V4L2_CID_HUE:
+ reg = saa7191_read_reg(sd, SAA7191_REG_HUEC);
if (reg < 0x80)
reg += 0x80;
else
@@ -452,18 +449,18 @@ static int saa7191_get_control(struct i2c_client *client,
ctrl->value = (s32)reg;
break;
case SAA7191_CONTROL_VTRC:
- reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+ reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0;
break;
case SAA7191_CONTROL_LUMA_DELAY:
- reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK)
>> SAA7191_CTL3_YDEL_SHIFT;
if (ctrl->value >= 4)
ctrl->value -= 8;
break;
case SAA7191_CONTROL_VNR:
- reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
+ reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK)
>> SAA7191_CTL4_VNOI_SHIFT;
break;
@@ -474,18 +471,17 @@ static int saa7191_get_control(struct i2c_client *client,
return ret;
}
-static int saa7191_set_control(struct i2c_client *client,
- struct saa7191_control *ctrl)
+static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
u8 reg;
int ret = 0;
- switch (ctrl->type) {
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
case SAA7191_CONTROL_BANDPASS_WEIGHT:
case SAA7191_CONTROL_CORING:
- reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
- switch (ctrl->type) {
+ reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
reg &= ~SAA7191_LUMA_BPSS_MASK;
reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT)
@@ -502,12 +498,12 @@ static int saa7191_set_control(struct i2c_client *client,
& SAA7191_LUMA_CORI_MASK;
break;
}
- ret = saa7191_write_reg(client, SAA7191_REG_LUMA, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_LUMA, reg);
break;
case SAA7191_CONTROL_FORCE_COLOUR:
case SAA7191_CONTROL_CHROMA_GAIN:
- reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
- if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) {
+ reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+ if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) {
if (ctrl->value)
reg |= SAA7191_GAIN_COLO;
else
@@ -517,41 +513,41 @@ static int saa7191_set_control(struct i2c_client *client,
reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT)
& SAA7191_GAIN_LFIS_MASK;
}
- ret = saa7191_write_reg(client, SAA7191_REG_GAIN, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg);
break;
- case SAA7191_CONTROL_HUE:
+ case V4L2_CID_HUE:
reg = ctrl->value & 0xff;
if (reg < 0x80)
reg += 0x80;
else
reg -= 0x80;
- ret = saa7191_write_reg(client, SAA7191_REG_HUEC, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg);
break;
case SAA7191_CONTROL_VTRC:
- reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+ reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
if (ctrl->value)
reg |= SAA7191_STDC_VTRC;
else
reg &= ~SAA7191_STDC_VTRC;
- ret = saa7191_write_reg(client, SAA7191_REG_STDC, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_STDC, reg);
break;
case SAA7191_CONTROL_LUMA_DELAY: {
s32 value = ctrl->value;
if (value < 0)
value += 8;
- reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
reg &= ~SAA7191_CTL3_YDEL_MASK;
reg |= (value << SAA7191_CTL3_YDEL_SHIFT)
& SAA7191_CTL3_YDEL_MASK;
- ret = saa7191_write_reg(client, SAA7191_REG_CTL3, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg);
break;
}
case SAA7191_CONTROL_VNR:
- reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
+ reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
reg &= ~SAA7191_CTL4_VNOI_MASK;
reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT)
& SAA7191_CTL4_VNOI_MASK;
- ret = saa7191_write_reg(client, SAA7191_REG_CTL4, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg);
break;
default:
ret = -EINVAL;
@@ -562,247 +558,111 @@ static int saa7191_set_control(struct i2c_client *client,
/* I2C-interface */
-static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
+static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
- int err = 0;
- struct saa7191 *decoder;
- struct i2c_client *client;
-
- printk(KERN_INFO "Philips SAA7191 driver version %s\n",
- SAA7191_MODULE_VERSION);
-
- client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
- if (!decoder) {
- err = -ENOMEM;
- goto out_free_client;
- }
-
- client->addr = addr;
- client->adapter = adap;
- client->driver = &i2c_driver_saa7191;
- client->flags = 0;
- strcpy(client->name, "saa7191 client");
- i2c_set_clientdata(client, decoder);
-
- decoder->client = client;
-
- err = i2c_attach_client(client);
- if (err)
- goto out_free_decoder;
-
- err = saa7191_write_block(client, sizeof(initseq), initseq);
- if (err) {
- printk(KERN_ERR "SAA7191 initialization failed\n");
- goto out_detach_client;
- }
-
- printk(KERN_INFO "SAA7191 initialized\n");
-
- decoder->input = SAA7191_INPUT_COMPOSITE;
- decoder->norm = SAA7191_NORM_PAL;
-
- err = saa7191_autodetect_norm(client);
- if (err && (err != -EBUSY)) {
- printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
- }
+ u8 status_reg;
+ int res = V4L2_IN_ST_NO_SIGNAL;
+ if (saa7191_read_status(sd, &status_reg))
+ return -EIO;
+ if ((status_reg & SAA7191_STATUS_HLCK) == 0)
+ res = 0;
+ if (!(status_reg & SAA7191_STATUS_CODE))
+ res |= V4L2_IN_ST_NO_COLOR;
+ *status = res;
return 0;
-
-out_detach_client:
- i2c_detach_client(client);
-out_free_decoder:
- kfree(decoder);
-out_free_client:
- kfree(client);
- return err;
}
-static int saa7191_probe(struct i2c_adapter *adap)
-{
- /* Always connected to VINO */
- if (adap->id == I2C_HW_SGI_VINO)
- return saa7191_attach(adap, SAA7191_ADDR, 0);
- /* Feel free to add probe here :-) */
- return -ENODEV;
-}
-static int saa7191_detach(struct i2c_client *client)
+static int saa7191_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
{
- struct saa7191 *decoder = i2c_get_clientdata(client);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- i2c_detach_client(client);
- kfree(decoder);
- kfree(client);
- return 0;
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0);
}
-static int saa7191_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
-{
- struct saa7191 *decoder = i2c_get_clientdata(client);
+/* ----------------------------------------------------------------------- */
- switch (cmd) {
- case DECODER_GET_CAPABILITIES: {
- struct video_decoder_capability *cap = arg;
+static const struct v4l2_subdev_core_ops saa7191_core_ops = {
+ .g_chip_ident = saa7191_g_chip_ident,
+ .g_ctrl = saa7191_g_ctrl,
+ .s_ctrl = saa7191_s_ctrl,
+};
- cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
- VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
- cap->inputs = (client->adapter->id == I2C_HW_SGI_VINO) ? 2 : 1;
- cap->outputs = 1;
- break;
- }
- case DECODER_GET_STATUS: {
- int *iarg = arg;
- u8 status;
- int res = 0;
+static const struct v4l2_subdev_tuner_ops saa7191_tuner_ops = {
+ .s_std = saa7191_s_std,
+};
- if (saa7191_read_status(client, &status)) {
- return -EIO;
- }
- if ((status & SAA7191_STATUS_HLCK) == 0)
- res |= DECODER_STATUS_GOOD;
- if (status & SAA7191_STATUS_CODE)
- res |= DECODER_STATUS_COLOR;
- switch (decoder->norm) {
- case SAA7191_NORM_NTSC:
- res |= DECODER_STATUS_NTSC;
- break;
- case SAA7191_NORM_PAL:
- res |= DECODER_STATUS_PAL;
- break;
- case SAA7191_NORM_SECAM:
- res |= DECODER_STATUS_SECAM;
- break;
- case SAA7191_NORM_AUTO:
- default:
- if (status & SAA7191_STATUS_FIDT)
- res |= DECODER_STATUS_NTSC;
- else
- res |= DECODER_STATUS_PAL;
- break;
- }
- *iarg = res;
- break;
- }
- case DECODER_SET_NORM: {
- int *iarg = arg;
-
- switch (*iarg) {
- case VIDEO_MODE_AUTO:
- return saa7191_autodetect_norm(client);
- case VIDEO_MODE_PAL:
- return saa7191_set_norm(client, SAA7191_NORM_PAL);
- case VIDEO_MODE_NTSC:
- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
- case VIDEO_MODE_SECAM:
- return saa7191_set_norm(client, SAA7191_NORM_SECAM);
- default:
- return -EINVAL;
- }
- break;
- }
- case DECODER_SET_INPUT: {
- int *iarg = arg;
-
- switch (client->adapter->id) {
- case I2C_HW_SGI_VINO:
- return saa7191_set_input(client, *iarg);
- default:
- if (*iarg != 0)
- return -EINVAL;
- }
- break;
- }
- case DECODER_SET_OUTPUT: {
- int *iarg = arg;
+static const struct v4l2_subdev_video_ops saa7191_video_ops = {
+ .s_routing = saa7191_s_routing,
+ .querystd = saa7191_querystd,
+ .g_input_status = saa7191_g_input_status,
+};
- /* not much choice of outputs */
- if (*iarg != 0)
- return -EINVAL;
- break;
- }
- case DECODER_ENABLE_OUTPUT: {
- /* Always enabled */
- break;
- }
- case DECODER_SET_PICTURE: {
- struct video_picture *pic = arg;
- unsigned val;
- int err;
+static const struct v4l2_subdev_ops saa7191_ops = {
+ .core = &saa7191_core_ops,
+ .video = &saa7191_video_ops,
+};
- val = (pic->hue >> 8) - 0x80;
+static int saa7191_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = 0;
+ struct saa7191 *decoder;
+ struct v4l2_subdev *sd;
- err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
- if (err)
- return -EIO;
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
- break;
- }
- case DECODER_SAA7191_GET_STATUS: {
- struct saa7191_status *status = arg;
- u8 status_reg;
+ decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder)
+ return -ENOMEM;
- if (saa7191_read_status(client, &status_reg))
- return -EIO;
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa7191_ops);
- status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
- ? 1 : 0;
- status->signal_60hz = (status_reg & SAA7191_STATUS_FIDT)
- ? 1 : 0;
- status->color = (status_reg & SAA7191_STATUS_CODE) ? 1 : 0;
+ err = saa7191_write_block(sd, sizeof(initseq), initseq);
+ if (err) {
+ printk(KERN_ERR "SAA7191 initialization failed\n");
+ kfree(decoder);
+ return err;
+ }
- status->input = decoder->input;
- status->norm = decoder->norm;
+ printk(KERN_INFO "SAA7191 initialized\n");
- break;
- }
- case DECODER_SAA7191_SET_NORM: {
- int *norm = arg;
-
- switch (*norm) {
- case SAA7191_NORM_AUTO:
- return saa7191_autodetect_norm(client);
- case SAA7191_NORM_AUTO_EXT:
- return saa7191_autodetect_norm_extended(client);
- default:
- return saa7191_set_norm(client, *norm);
- }
- }
- case DECODER_SAA7191_GET_CONTROL: {
- return saa7191_get_control(client, arg);
- }
- case DECODER_SAA7191_SET_CONTROL: {
- return saa7191_set_control(client, arg);
- }
- default:
- return -EINVAL;
- }
+ decoder->input = SAA7191_INPUT_COMPOSITE;
+ decoder->norm = V4L2_STD_PAL;
+
+ err = saa7191_autodetect_norm(sd);
+ if (err && (err != -EBUSY))
+ printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
return 0;
}
-static struct i2c_driver i2c_driver_saa7191 = {
- .driver = {
- .name = "saa7191",
- },
- .id = I2C_DRIVERID_SAA7191,
- .attach_adapter = saa7191_probe,
- .detach_client = saa7191_detach,
- .command = saa7191_command
-};
-
-static int saa7191_init(void)
+static int saa7191_remove(struct i2c_client *client)
{
- return i2c_add_driver(&i2c_driver_saa7191);
-}
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-static void saa7191_exit(void)
-{
- i2c_del_driver(&i2c_driver_saa7191);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_saa7191(sd));
+ return 0;
}
-module_init(saa7191_init);
-module_exit(saa7191_exit);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa7191_id[] = {
+ { "saa7191", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7191_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7191",
+ .probe = saa7191_probe,
+ .remove = saa7191_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa7191_id,
+#endif
+};
diff --git a/linux/drivers/media/video/saa7191.h b/linux/drivers/media/video/saa7191.h
index a2310da19..803c74d60 100644
--- a/linux/drivers/media/video/saa7191.h
+++ b/linux/drivers/media/video/saa7191.h
@@ -176,11 +176,9 @@
#define SAA7191_INPUT_COMPOSITE 0
#define SAA7191_INPUT_SVIDEO 1
-#define SAA7191_NORM_AUTO 0
#define SAA7191_NORM_PAL 1
#define SAA7191_NORM_NTSC 2
#define SAA7191_NORM_SECAM 3
-#define SAA7191_NORM_AUTO_EXT 4 /* extended auto-detection */
struct saa7191_status {
/* 0=no signal, 1=signal detected */
@@ -232,24 +230,16 @@ struct saa7191_status {
#define SAA7191_VNR_MAX 0x03
#define SAA7191_VNR_DEFAULT 0x00
-#define SAA7191_CONTROL_BANDPASS 0
-#define SAA7191_CONTROL_BANDPASS_WEIGHT 1
-#define SAA7191_CONTROL_CORING 2
-#define SAA7191_CONTROL_FORCE_COLOUR 3 /* boolean */
-#define SAA7191_CONTROL_CHROMA_GAIN 4
-#define SAA7191_CONTROL_HUE 5
-#define SAA7191_CONTROL_VTRC 6 /* boolean */
-#define SAA7191_CONTROL_LUMA_DELAY 7
-#define SAA7191_CONTROL_VNR 8
-
-struct saa7191_control {
- u8 type;
- s32 value;
-};
+#define SAA7191_CONTROL_BANDPASS (V4L2_CID_PRIVATE_BASE + 0)
+#define SAA7191_CONTROL_BANDPASS_WEIGHT (V4L2_CID_PRIVATE_BASE + 1)
+#define SAA7191_CONTROL_CORING (V4L2_CID_PRIVATE_BASE + 2)
+#define SAA7191_CONTROL_FORCE_COLOUR (V4L2_CID_PRIVATE_BASE + 3)
+#define SAA7191_CONTROL_CHROMA_GAIN (V4L2_CID_PRIVATE_BASE + 4)
+#define SAA7191_CONTROL_VTRC (V4L2_CID_PRIVATE_BASE + 5)
+#define SAA7191_CONTROL_LUMA_DELAY (V4L2_CID_PRIVATE_BASE + 6)
+#define SAA7191_CONTROL_VNR (V4L2_CID_PRIVATE_BASE + 7)
#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status)
#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int)
-#define DECODER_SAA7191_GET_CONTROL _IOR('d', 197, struct saa7191_control)
-#define DECODER_SAA7191_SET_CONTROL _IOW('d', 198, struct saa7191_control)
#endif
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index 29ff02802..cd796b33f 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -95,7 +95,7 @@ struct sh_mobile_ceu_dev {
spinlock_t lock;
struct list_head capture;
struct videobuf_buffer *active;
- int is_interlace;
+ int is_interlaced;
struct sh_mobile_ceu_info *pdata;
@@ -175,6 +175,7 @@ static void free_buffer(struct videobuf_queue *vq,
if (in_interrupt())
BUG();
+ videobuf_waiton(&buf->vb, 0, 0);
videobuf_dma_contig_free(vq, &buf->vb);
dev_dbg(&icd->dev, "%s freed\n", __func__);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -206,7 +207,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_interlace) {
+ if (pcdev->is_interlaced) {
phys_addr_bottom = phys_addr_top + icd->width;
ceu_write(pcdev, CDBYR, phys_addr_bottom);
}
@@ -218,7 +219,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
case V4L2_PIX_FMT_NV61:
phys_addr_top += icd->width * icd->height;
ceu_write(pcdev, CDACR, phys_addr_top);
- if (pcdev->is_interlace) {
+ if (pcdev->is_interlaced) {
phys_addr_bottom = phys_addr_top + icd->width;
ceu_write(pcdev, CDBCR, phys_addr_bottom);
}
@@ -482,7 +483,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
ceu_write(pcdev, CAMCR, value);
ceu_write(pcdev, CAPCR, 0x00300000);
- ceu_write(pcdev, CAIFR, (pcdev->is_interlace) ? 0x101 : 0);
+ ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0);
mdelay(1);
@@ -498,7 +499,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
}
height = icd->height;
- if (pcdev->is_interlace) {
+ if (pcdev->is_interlaced) {
height /= 2;
cdwdr_width *= 2;
}
@@ -639,24 +640,30 @@ add_single_format:
return formats;
}
+static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
+{
+ return icd->ops->set_crop(icd, rect);
+}
+
static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+ 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 v4l2_format cam_f = *f;
int ret;
- if (!pixfmt)
- return icd->ops->set_fmt(icd, pixfmt, rect);
-
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
- ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
+ cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
+ ret = icd->ops->set_fmt(icd, &cam_f);
if (!ret) {
icd->buswidth = xlate->buswidth;
@@ -706,13 +713,13 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
switch (f->fmt.pix.field) {
case V4L2_FIELD_INTERLACED:
- pcdev->is_interlace = 1;
+ pcdev->is_interlaced = 1;
break;
case V4L2_FIELD_ANY:
f->fmt.pix.field = V4L2_FIELD_NONE;
/* fall-through */
case V4L2_FIELD_NONE:
- pcdev->is_interlace = 0;
+ pcdev->is_interlaced = 0;
break;
default:
ret = -EINVAL;
@@ -778,7 +785,8 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
&sh_mobile_ceu_videobuf_ops,
&ici->dev, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_ANY,
+ pcdev->is_interlaced ?
+ V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
sizeof(struct sh_mobile_ceu_buffer),
icd);
}
@@ -788,6 +796,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.add = sh_mobile_ceu_add_device,
.remove = sh_mobile_ceu_remove_device,
.get_formats = sh_mobile_ceu_get_formats,
+ .set_crop = sh_mobile_ceu_set_crop,
.set_fmt = sh_mobile_ceu_set_fmt,
.try_fmt = sh_mobile_ceu_try_fmt,
.reqbufs = sh_mobile_ceu_reqbufs,
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
index 41dfb60f4..38a716020 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -96,9 +96,7 @@ static const struct usb_device_id sn9c102_id_table[] = {
#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
-#endif
{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index 356b77e10..da6d224eb 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -31,6 +31,10 @@
#include <media/soc_camera.h>
#include "compat.h"
+/* Default to VGA resolution */
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
+
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock);
@@ -257,6 +261,46 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
vfree(icd->user_formats);
}
+/* Called with .vb_lock held */
+static int soc_camera_set_fmt(struct soc_camera_file *icf,
+ struct v4l2_format *f)
+{
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int ret;
+
+ /* We always call try_fmt() before set_fmt() or set_crop() */
+ ret = ici->ops->try_fmt(icd, f);
+ if (ret < 0)
+ return ret;
+
+ ret = ici->ops->set_fmt(icd, f);
+ if (ret < 0) {
+ return ret;
+ } else if (!icd->current_fmt ||
+ icd->current_fmt->fourcc != pix->pixelformat) {
+ dev_err(&ici->dev,
+ "Host driver hasn't set up current format correctly!\n");
+ return -EINVAL;
+ }
+
+ icd->width = pix->width;
+ icd->height = pix->height;
+ icf->vb_vidq.field =
+ icd->field = pix->field;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
+ f->type);
+
+ dev_dbg(&icd->dev, "set width: %d height: %d\n",
+ icd->width, icd->height);
+
+ /* set physical bus parameters */
+ return ici->ops->set_bus_param(icd, pix->pixelformat);
+}
+
static int soc_camera_open(struct file *file)
{
struct video_device *vdev;
@@ -298,14 +342,28 @@ static int soc_camera_open(struct file *file)
/* Now we really have to activate the camera */
if (icd->use_count == 1) {
- ret = soc_camera_init_user_formats(icd);
- if (ret < 0)
- goto eiufmt;
+ /* Restore parameters before the last close() per V4L2 API */
+ struct v4l2_format f = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .fmt.pix = {
+ .width = icd->width,
+ .height = icd->height,
+ .field = icd->field,
+ .pixelformat = icd->current_fmt->fourcc,
+ .colorspace = icd->current_fmt->colorspace,
+ },
+ };
+
ret = ici->ops->add(icd);
if (ret < 0) {
dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
goto eiciadd;
}
+
+ /* Try to configure with default parameters */
+ ret = soc_camera_set_fmt(icf, &f);
+ if (ret < 0)
+ goto esfmt;
}
mutex_unlock(&icd->video_lock);
@@ -317,10 +375,13 @@ static int soc_camera_open(struct file *file)
return 0;
- /* First two errors are entered with the .video_lock held */
+ /*
+ * First three errors are entered with the .video_lock held
+ * and use_count == 1
+ */
+esfmt:
+ ici->ops->remove(icd);
eiciadd:
- soc_camera_free_user_formats(icd);
-eiufmt:
icd->use_count--;
mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
@@ -340,10 +401,9 @@ static int soc_camera_close(struct file *file)
mutex_lock(&icd->video_lock);
icd->use_count--;
- if (!icd->use_count) {
+ if (!icd->use_count)
ici->ops->remove(icd);
- soc_camera_free_user_formats(icd);
- }
+
mutex_unlock(&icd->video_lock);
module_put(icd->ops->owner);
@@ -416,18 +476,10 @@ static int soc_camera_s_fmt_vid_cap(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_pix_format *pix = &f->fmt.pix;
- __u32 pixfmt = pix->pixelformat;
int ret;
- struct v4l2_rect rect;
WARN_ON(priv != file->private_data);
- ret = soc_camera_try_fmt_vid_cap(file, priv, f);
- if (ret < 0)
- return ret;
-
mutex_lock(&icf->vb_vidq.vb_lock);
if (videobuf_queue_is_busy(&icf->vb_vidq)) {
@@ -436,33 +488,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
goto unlock;
}
- rect.left = icd->x_current;
- rect.top = icd->y_current;
- rect.width = pix->width;
- rect.height = pix->height;
- ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
- if (ret < 0) {
- goto unlock;
- } else if (!icd->current_fmt ||
- icd->current_fmt->fourcc != pixfmt) {
- dev_err(&ici->dev,
- "Host driver hasn't set up current format correctly!\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- icd->width = rect.width;
- icd->height = rect.height;
- icf->vb_vidq.field = pix->field;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
- f->type);
-
- dev_dbg(&icd->dev, "set width: %d height: %d\n",
- icd->width, icd->height);
-
- /* set physical bus parameters */
- ret = ici->ops->set_bus_param(icd, pixfmt);
+ ret = soc_camera_set_fmt(icf, f);
unlock:
mutex_unlock(&icf->vb_vidq.vb_lock);
@@ -649,8 +675,8 @@ static int soc_camera_cropcap(struct file *file, void *fh,
a->bounds.height = icd->height_max;
a->defrect.left = icd->x_min;
a->defrect.top = icd->y_min;
- a->defrect.width = 640;
- a->defrect.height = 480;
+ a->defrect.width = DEFAULT_WIDTH;
+ a->defrect.height = DEFAULT_HEIGHT;
a->pixelaspect.numerator = 1;
a->pixelaspect.denominator = 1;
@@ -686,7 +712,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
/* Cropping is allowed during a running capture, guard consistency */
mutex_lock(&icf->vb_vidq.vb_lock);
- ret = ici->ops->set_fmt(icd, 0, &a->c);
+ ret = ici->ops->set_crop(icd, &a->c);
if (!ret) {
icd->width = a->c.width;
icd->height = a->c.height;
@@ -845,9 +871,18 @@ static int soc_camera_probe(struct device *dev)
qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
icd->exposure = qctrl ? qctrl->default_value :
(unsigned short)~0;
+
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eiufmt;
+
+ icd->height = DEFAULT_HEIGHT;
+ icd->width = DEFAULT_WIDTH;
+ icd->field = V4L2_FIELD_ANY;
}
- ici->ops->remove(icd);
+eiufmt:
+ ici->ops->remove(icd);
eiadd:
mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
@@ -866,6 +901,8 @@ static int soc_camera_remove(struct device *dev)
if (icd->ops->remove)
icd->ops->remove(icd);
+ soc_camera_free_user_formats(icd);
+
return 0;
}
@@ -919,6 +956,7 @@ int soc_camera_host_register(struct soc_camera_host *ici)
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 ||
@@ -999,6 +1037,7 @@ int soc_camera_device_register(struct soc_camera_device *icd)
!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 ||
diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c
index 013ab06e3..c48676356 100644
--- a/linux/drivers/media/video/soc_camera_platform.c
+++ b/linux/drivers/media/video/soc_camera_platform.c
@@ -79,8 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *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,
- __u32 pixfmt, struct v4l2_rect *rect)
+ struct v4l2_format *f)
{
return 0;
}
@@ -125,6 +131,7 @@ static struct soc_camera_ops soc_camera_platform_ops = {
.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,
diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c
index 3af084640..7cbc4f736 100644
--- a/linux/drivers/media/video/stk-webcam.c
+++ b/linux/drivers/media/video/stk-webcam.c
@@ -934,8 +934,6 @@ static int stk_vidioc_s_ctrl(struct file *filp,
static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_fmtdesc *fmtd)
{
- fmtd->flags = 0;
-
switch (fmtd->index) {
case 0:
fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
@@ -993,7 +991,6 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
pix_format->height = stk_sizes[i].h;
pix_format->field = V4L2_FIELD_NONE;
pix_format->colorspace = V4L2_COLORSPACE_SRGB;
- pix_format->priv = 0;
pix_format->pixelformat = dev->vsettings.palette;
if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
pix_format->bytesperline = pix_format->width;
@@ -1116,8 +1113,6 @@ static int stk_vidioc_reqbufs(struct file *filp,
if (dev == NULL)
return -ENODEV;
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
if (rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if (is_streaming(dev)
@@ -1140,16 +1135,10 @@ static int stk_vidioc_reqbufs(struct file *filp,
static int stk_vidioc_querybuf(struct file *filp,
void *priv, struct v4l2_buffer *buf)
{
- int index;
struct stk_camera *dev = priv;
struct stk_sio_buffer *sbuf;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- index = buf->index;
-
- if (index < 0 || index >= dev->n_sbufs)
+ if (buf->index < 0 || buf->index >= dev->n_sbufs)
return -EINVAL;
sbuf = dev->sio_bufs + buf->index;
*buf = sbuf->v4lbuf;
@@ -1162,8 +1151,6 @@ static int stk_vidioc_qbuf(struct file *filp,
struct stk_camera *dev = priv;
struct stk_sio_buffer *sbuf;
unsigned long flags;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
if (buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
@@ -1190,8 +1177,7 @@ static int stk_vidioc_dqbuf(struct file *filp,
unsigned long flags;
int ret;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
- || !is_streaming(dev))
+ if (!is_streaming(dev))
return -EINVAL;
if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
@@ -1250,16 +1236,10 @@ static int stk_vidioc_streamoff(struct file *filp,
static int stk_vidioc_g_parm(struct file *filp,
void *priv, struct v4l2_streamparm *sp)
{
- if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp->parm.capture.capability = 0;
- sp->parm.capture.capturemode = 0;
/*FIXME This is not correct */
sp->parm.capture.timeperframe.numerator = 1;
sp->parm.capture.timeperframe.denominator = 30;
sp->parm.capture.readbuffers = 2;
- sp->parm.capture.extendedmode = 0;
return 0;
}
diff --git a/linux/drivers/media/video/tlv320aic23b.c b/linux/drivers/media/video/tlv320aic23b.c
index 46671fb87..1eac4f7e7 100644
--- a/linux/drivers/media/video/tlv320aic23b.c
+++ b/linux/drivers/media/video/tlv320aic23b.c
@@ -31,16 +31,18 @@
#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-i2c-drv.h>
#include "compat.h"
MODULE_DESCRIPTION("tlv320aic23b driver");
MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
+#endif
/* ----------------------------------------------------------------------- */
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 0188d87ea..9960fb357 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -365,7 +365,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
}
t->type = type;
- t->config = new_config;
+ /* prevent invalid config values */
+ t->config = ((new_config >= 0) && (new_config < 256)) ? new_config : 0;
if (tuner_callback != NULL) {
tuner_dbg("defining GPIO callback\n");
t->fe.callback = tuner_callback;
@@ -453,7 +454,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
struct dvb_tuner_ops *xc_tuner_ops;
xc5000_cfg.i2c_address = t->i2c->addr;
- xc5000_cfg.if_khz = 5380;
+ /* if_khz will be set when the digital dvb_attach() occurs */
+ xc5000_cfg.if_khz = 0;
if (!dvb_attach(xc5000_attach,
&t->fe, t->i2c->adapter, &xc5000_cfg))
goto attach_failed;
diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c
index 755418a31..39d796908 100644
--- a/linux/drivers/media/video/tvaudio.c
+++ b/linux/drivers/media/video/tvaudio.c
@@ -57,7 +57,7 @@ MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
/* our structs */
-#define MAXREGS 64
+#define MAXREGS 256
struct CHIPSTATE;
typedef int (*getvalue)(int);
@@ -1055,6 +1055,116 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
return 0;
}
+/* ---------------------------------------------------------------------- */
+/* audio chip description - defines+functions for tda9875 */
+/* The TDA9875 is made by Philips Semiconductor
+ * http://www.semiconductors.philips.com
+ * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
+ *
+ */
+
+/* subaddresses for TDA9875 */
+#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/
+#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */
+#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/
+#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/
+
+#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/
+#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/
+#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/
+#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/
+
+#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/
+#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/
+#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/
+#define TDA9875_MVL 0x1a /* Main volume gauche */
+#define TDA9875_MVR 0x1b /* Main volume droite */
+#define TDA9875_MBA 0x1d /* Main Basse */
+#define TDA9875_MTR 0x1e /* Main treble */
+#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/
+#define TDA9875_AVL 0x20 /* Auxilary volume gauche */
+#define TDA9875_AVR 0x21 /* Auxilary volume droite */
+#define TDA9875_ABA 0x22 /* Auxilary Basse */
+#define TDA9875_ATR 0x23 /* Auxilary treble */
+
+#define TDA9875_MSR 0x02 /* Monitor select register */
+#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */
+#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */
+#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */
+#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */
+#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */
+#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */
+#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/
+#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/
+#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/
+
+/* values */
+#define TDA9875_MUTE_ON 0xff /* general mute */
+#define TDA9875_MUTE_OFF 0xcc /* general no mute */
+
+static int tda9875_initialize(struct CHIPSTATE *chip)
+{
+ chip_write(chip, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
+ chip_write(chip, TDA9875_MSR, 0x03); /* Monitor 0b00000XXX*/
+ chip_write(chip, TDA9875_C1MSB, 0x00); /*Car1(FM) MSB XMHz*/
+ chip_write(chip, TDA9875_C1MIB, 0x00); /*Car1(FM) MIB XMHz*/
+ chip_write(chip, TDA9875_C1LSB, 0x00); /*Car1(FM) LSB XMHz*/
+ chip_write(chip, TDA9875_C2MSB, 0x00); /*Car2(NICAM) MSB XMHz*/
+ chip_write(chip, TDA9875_C2MIB, 0x00); /*Car2(NICAM) MIB XMHz*/
+ chip_write(chip, TDA9875_C2LSB, 0x00); /*Car2(NICAM) LSB XMHz*/
+ chip_write(chip, TDA9875_DCR, 0x00); /*Demod config 0x00*/
+ chip_write(chip, TDA9875_DEEM, 0x44); /*DE-Emph 0b0100 0100*/
+ chip_write(chip, TDA9875_FMAT, 0x00); /*FM Matrix reg 0x00*/
+ chip_write(chip, TDA9875_SC1, 0x00); /* SCART 1 (SC1)*/
+ chip_write(chip, TDA9875_SC2, 0x01); /* SCART 2 (sc2)*/
+
+ chip_write(chip, TDA9875_CH1V, 0x10); /* Channel volume 1 mute*/
+ chip_write(chip, TDA9875_CH2V, 0x10); /* Channel volume 2 mute */
+ chip_write(chip, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
+ chip_write(chip, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
+ chip_write(chip, TDA9875_LOSR, 0x00); /* line out (in:mono)*/
+ chip_write(chip, TDA9875_AER, 0x00); /*06 Effect (AVL+PSEUDO) */
+ chip_write(chip, TDA9875_MCS, 0x44); /* Main ch select (DAC) */
+ chip_write(chip, TDA9875_MVL, 0x03); /* Vol Main left 10dB */
+ chip_write(chip, TDA9875_MVR, 0x03); /* Vol Main right 10dB*/
+ chip_write(chip, TDA9875_MBA, 0x00); /* Main Bass Main 0dB*/
+ chip_write(chip, TDA9875_MTR, 0x00); /* Main Treble Main 0dB*/
+ chip_write(chip, TDA9875_ACS, 0x44); /* Aux chan select (dac)*/
+ chip_write(chip, TDA9875_AVL, 0x00); /* Vol Aux left 0dB*/
+ chip_write(chip, TDA9875_AVR, 0x00); /* Vol Aux right 0dB*/
+ chip_write(chip, TDA9875_ABA, 0x00); /* Aux Bass Main 0dB*/
+ chip_write(chip, TDA9875_ATR, 0x00); /* Aux Aigus Main 0dB*/
+
+ chip_write(chip, TDA9875_MUT, 0xcc); /* General mute */
+ return 0;
+}
+
+static int tda9875_volume(int val) { return (unsigned char)(val / 602 - 84); }
+static int tda9875_bass(int val) { return (unsigned char)(max(-12, val / 2115 - 15)); }
+static int tda9875_treble(int val) { return (unsigned char)(val / 2622 - 12); }
+
+/* ----------------------------------------------------------------------- */
+
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda9875_checkit(struct CHIPSTATE *chip)
+{
+ struct v4l2_subdev *sd = &chip->sd;
+ int dic, rev;
+
+ dic = chip_read2(chip, 254);
+ rev = chip_read2(chip, 255);
+
+ if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
+ v4l2_info(sd, "found tda9875%s rev. %d.\n",
+ dic == 0 ? "" : "A", rev);
+ return 1;
+ }
+ return 0;
+}
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - defines+functions for tea6420 */
@@ -1288,6 +1398,7 @@ static int tda9850 = 1;
static int tda9855 = 1;
static int tda9873 = 1;
static int tda9874a = 1;
+static int tda9875 = 1;
static int tea6300; /* default 0 - address clash with msp34xx */
static int tea6320; /* default 0 - address clash with msp34xx */
static int tea6420 = 1;
@@ -1300,6 +1411,7 @@ module_param(tda9850, int, 0444);
module_param(tda9855, int, 0444);
module_param(tda9873, int, 0444);
module_param(tda9874a, int, 0444);
+module_param(tda9875, int, 0444);
module_param(tea6300, int, 0444);
module_param(tea6320, int, 0444);
module_param(tea6420, int, 0444);
@@ -1357,6 +1469,26 @@ static struct CHIPDESC chiplist[] = {
.setmode = tda9874a_setmode,
},
{
+ .name = "tda9875",
+ .insmodopt = &tda9875,
+ .addr_lo = I2C_ADDR_TDA9875 >> 1,
+ .addr_hi = I2C_ADDR_TDA9875 >> 1,
+ .flags = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+ /* callbacks */
+ .initialize = tda9875_initialize,
+ .checkit = tda9875_checkit,
+ .volfunc = tda9875_volume,
+ .bassfunc = tda9875_bass,
+ .treblefunc = tda9875_treble,
+ .leftreg = TDA9875_MVL,
+ .rightreg = TDA9875_MVR,
+ .bassreg = TDA9875_MBA,
+ .treblereg = TDA9875_MTR,
+ .leftinit = 58880,
+ .rightinit = 58880,
+ },
+ {
.name = "tda9850",
.insmodopt = &tda9850,
.addr_lo = I2C_ADDR_TDA985x_L >> 1,
@@ -1519,6 +1651,8 @@ static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
+ if (!(desc->flags & CHIP_HAS_INPUTSEL))
+ break;
ctrl->value=chip->muted;
return 0;
case V4L2_CID_AUDIO_VOLUME:
@@ -1560,6 +1694,9 @@ static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
+ if (!(desc->flags & CHIP_HAS_INPUTSEL))
+ break;
+
if (ctrl->value < 0 || ctrl->value >= 2)
return -ERANGE;
chip->muted = ctrl->value;
@@ -1644,7 +1781,9 @@ static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
switch (qc->id) {
case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ if (desc->flags & CHIP_HAS_INPUTSEL)
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ break;
case V4L2_CID_AUDIO_VOLUME:
if (desc->flags & CHIP_HAS_VOLUME)
return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
@@ -1669,7 +1808,9 @@ static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *
struct CHIPSTATE *chip = to_state(sd);
struct CHIPDESC *desc = chip->desc;
- if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
+ if (!(desc->flags & CHIP_HAS_INPUTSEL))
+ return 0;
+ if (rt->input >= 4)
return -EINVAL;
/* There are four inputs: tuner, radio, extern and intern. */
chip->input = rt->input;
@@ -1686,8 +1827,11 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
struct CHIPDESC *desc = chip->desc;
int mode = 0;
+ if (!desc->setmode)
+ return 0;
if (chip->radio)
return 0;
+
switch (vt->audmode) {
case V4L2_TUNER_MODE_MONO:
case V4L2_TUNER_MODE_STEREO:
@@ -1703,7 +1847,7 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
}
chip->audmode = vt->audmode;
- if (desc->setmode && mode) {
+ if (mode) {
chip->watch_stereo = 0;
/* del_timer(&chip->wt); */
chip->mode = mode;
@@ -1718,15 +1862,17 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
struct CHIPDESC *desc = chip->desc;
int mode = V4L2_TUNER_MODE_MONO;
+ if (!desc->getmode)
+ return 0;
if (chip->radio)
return 0;
+
vt->audmode = chip->audmode;
vt->rxsubchans = 0;
vt->capability = V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
- if (desc->getmode)
- mode = desc->getmode(chip);
+ mode = desc->getmode(chip);
if (mode & V4L2_TUNER_MODE_MONO)
vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
@@ -1916,6 +2062,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
}
chip->thread = NULL;
+ init_timer(&chip->wt);
if (desc->flags & CHIP_NEED_CHECKMODE) {
if (!desc->getmode || !desc->setmode) {
/* This shouldn't be happen. Warn user, but keep working
@@ -1925,7 +2072,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
return 0;
}
/* start async thread */
- init_timer(&chip->wt);
chip->wt.function = chip_thread_wake;
chip->wt.data = (unsigned long)chip;
chip->thread = kthread_run(chip_thread, chip, client->name);
diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c
index acd601a52..cdea91aae 100644
--- a/linux/drivers/media/video/tveeprom.c
+++ b/linux/drivers/media/video/tveeprom.c
@@ -262,7 +262,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "MaxLinear MXL5005_v2"},
{ TUNER_PHILIPS_TDA8290, "Philips 18271_8295"},
/* 150-159 */
- { TUNER_ABSENT, "Xceive XC5000"},
+ { TUNER_XC5000, "Xceive XC5000"},
{ TUNER_ABSENT, "Xceive XC3028L"},
{ TUNER_ABSENT, "NXP 18271C2_716x"},
{ TUNER_ABSENT, "Xceive XC4000"},
diff --git a/linux/drivers/media/video/tw9910.c b/linux/drivers/media/video/tw9910.c
index ed8dca3bf..5c145085a 100644
--- a/linux/drivers/media/video/tw9910.c
+++ b/linux/drivers/media/video/tw9910.c
@@ -641,25 +641,12 @@ static int tw9910_set_register(struct soc_camera_device *icd,
}
#endif
-static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt,
- struct v4l2_rect *rect)
+static int tw9910_set_crop(struct soc_camera_device *icd,
+ struct v4l2_rect *rect)
{
struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
int ret = -EINVAL;
u8 val;
- int i;
-
- /*
- * check color format
- */
- for (i = 0 ; i < ARRAY_SIZE(tw9910_color_fmt) ; i++) {
- if (pixfmt == tw9910_color_fmt[i].fourcc) {
- ret = 0;
- break;
- }
- }
- if (ret < 0)
- goto tw9910_set_fmt_error;
/*
* select suitable norm
@@ -746,8 +733,33 @@ tw9910_set_fmt_error:
return ret;
}
+static int tw9910_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ 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 i;
+
+ /*
+ * check color format
+ */
+ for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++)
+ if (pix->pixelformat == tw9910_color_fmt[i].fourcc)
+ break;
+
+ if (i == ARRAY_SIZE(tw9910_color_fmt))
+ return -EINVAL;
+
+ return tw9910_set_crop(icd, &rect);
+}
+
static int tw9910_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
const struct tw9910_scale_ctrl *scale;
@@ -835,6 +847,7 @@ static struct soc_camera_ops tw9910_ops = {
.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,
diff --git a/linux/drivers/media/video/usbvideo/vicam.c b/linux/drivers/media/video/usbvideo/vicam.c
index 5a039b5d6..3b332ef52 100644
--- a/linux/drivers/media/video/usbvideo/vicam.c
+++ b/linux/drivers/media/video/usbvideo/vicam.c
@@ -489,7 +489,7 @@ initialize_camera(struct vicam_camera *cam)
#else
int err;
const struct ihex_binrec *rec;
- const struct firmware *fw;
+ const struct firmware *uninitialized_var(fw);
err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev);
if (err) {
diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c
index 7fe361668..734df263f 100644
--- a/linux/drivers/media/video/usbvision/usbvision-core.c
+++ b/linux/drivers/media/video/usbvision/usbvision-core.c
@@ -2524,7 +2524,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
urb->dev = dev;
urb->context = usbvision;
urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
- urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->interval = 1;
urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
urb->complete = usbvision_isocIrq;
diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c
index 33d79a5da..fa62a2fd7 100644
--- a/linux/drivers/media/video/usbvision/usbvision-video.c
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -697,7 +697,6 @@ static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- memset(a,0,sizeof(*a));
if(usbvision->radio) {
strcpy(a->name,"Radio");
} else {
@@ -721,10 +720,6 @@ static int vidioc_queryctrl (struct file *file, void *priv,
struct v4l2_queryctrl *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int id=ctrl->id;
-
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
call_all(usbvision, core, queryctrl, ctrl);
@@ -762,8 +757,7 @@ static int vidioc_reqbufs (struct file *file,
/* Check input validity:
the user must do a VIDEO CAPTURE and MMAP method. */
- if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (vr->memory != V4L2_MEMORY_MMAP))
+ if (vr->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if(usbvision->streaming == Stream_On) {
@@ -788,9 +782,6 @@ static int vidioc_querybuf (struct file *file,
/* FIXME : must control
that buffers are mapped (VIDIOC_REQBUFS has been called) */
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
if(vb->index>=usbvision->num_frames) {
return -EINVAL;
}
@@ -824,9 +815,6 @@ static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
unsigned long lock_flags;
/* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
if(vb->index>=usbvision->num_frames) {
return -EINVAL;
}
@@ -861,9 +849,6 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
struct usbvision_frame *f;
unsigned long lock_flags;
- if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
if (list_empty(&(usbvision->outqueue))) {
if (usbvision->streaming == Stream_Idle)
return -EINVAL;
@@ -929,11 +914,8 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
return -EINVAL;
}
- vfd->flags = 0;
- vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
- memset(vfd->reserved, 0, sizeof(vfd->reserved));
return 0;
}
@@ -1781,6 +1763,8 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
// At this time we ask to cancel outstanding URBs
usbvision_stop_isoc(usbvision);
+ v4l2_device_disconnect(&usbvision->v4l2_dev);
+
if (usbvision->power) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
diff --git a/linux/drivers/media/video/usbvision/usbvision.h b/linux/drivers/media/video/usbvision/usbvision.h
index dc86c2139..42a926799 100644
--- a/linux/drivers/media/video/usbvision/usbvision.h
+++ b/linux/drivers/media/video/usbvision/usbvision.h
@@ -6,7 +6,7 @@
* Dwaine Garden <dwainegarden@rogers.com>
*
*
- * Report problems to v4l MailingList : http://www.redhat.com/mailman/listinfo/video4linux-list
+ * Report problems to v4l MailingList: linux-media@vger.kernel.org
*
* This module is part of usbvision driver project.
* Updates to driver completed by Dwaine P. Garden
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index a5ce43102..b153575fb 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -570,6 +570,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_RED_BALANCE:
case V4L2_CID_BLUE_BALANCE:
case V4L2_CID_GAMMA:
+ case V4L2_CID_SHARPNESS:
qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
break;
case V4L2_CID_PAN_RELATIVE:
@@ -828,10 +829,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
#endif
BUG_ON(!dev);
-#ifdef MODULE
+
if (module_name)
request_module(module_name);
-#endif
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
/* Setup the i2c board info with the device type and
the device address. */
@@ -856,11 +857,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
We need better support from the kernel so that we
can easily wait for the load to finish. */
if (client == NULL || client->driver == NULL)
- return NULL;
+ goto error;
/* Lock the module so we can safely get the v4l2_subdev pointer */
if (!try_module_get(client->driver->driver.owner))
- return NULL;
+ goto error;
sd = i2c_get_clientdata(client);
/* Register with the v4l2_device which increases the module's
@@ -869,8 +870,15 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
sd = NULL;
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);
- return sd;
+error:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ /* If we have a client but no subdev, then something went wrong and
+ we must unregister the client. */
+ if (client && sd == NULL)
+ i2c_unregister_device(client);
+#endif
+ return sd;
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
@@ -889,10 +897,10 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
#endif
BUG_ON(!dev);
-#ifdef MODULE
+
if (module_name)
request_module(module_name);
-#endif
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
/* Setup the i2c board info with the device type and
the device address. */
@@ -918,11 +926,11 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
We need better support from the kernel so that we
can easily wait for the load to finish. */
if (client == NULL || client->driver == NULL)
- return NULL;
+ goto error;
/* Lock the module so we can safely get the v4l2_subdev pointer */
if (!try_module_get(client->driver->driver.owner))
- return NULL;
+ goto error;
sd = i2c_get_clientdata(client);
/* Register with the v4l2_device which increases the module's
@@ -931,6 +939,14 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
sd = NULL;
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);
+
+error:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ /* If we have a client but no subdev, then something went wrong and
+ we must unregister the client. */
+ if (client && sd == NULL)
+ i2c_unregister_device(client);
+#endif
return sd;
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
diff --git a/linux/drivers/media/video/v4l2-compat-ioctl32.c b/linux/drivers/media/video/v4l2-compat-ioctl32.c
index 05a356776..d9cee38cd 100644
--- a/linux/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/linux/drivers/media/video/v4l2-compat-ioctl32.c
@@ -1052,7 +1052,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_DBG_S_REGISTER:
case VIDIOC_DBG_G_REGISTER:
case VIDIOC_DBG_G_CHIP_IDENT:
- case VIDIOC_G_CHIP_IDENT_OLD:
case VIDIOC_S_HW_FREQ_SEEK:
ret = do_video_ioctl(file, cmd, arg);
break;
diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c
index e6dc1279a..2c4d38979 100644
--- a/linux/drivers/media/video/v4l2-dev.c
+++ b/linux/drivers/media/video/v4l2-dev.c
@@ -236,6 +236,23 @@ static long v4l2_unlocked_ioctl(struct file *filp,
return vdev->fops->unlocked_ioctl(filp, cmd, arg);
}
+#ifdef CONFIG_MMU
+#define v4l2_get_unmapped_area NULL
+#else
+static unsigned long v4l2_get_unmapped_area(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->get_unmapped_area)
+ return -ENOSYS;
+ if (video_is_unregistered(vdev))
+ return -ENODEV;
+ return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+}
+#endif
+
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
{
struct video_device *vdev = video_devdata(filp);
@@ -288,6 +305,7 @@ static const struct file_operations v4l2_unlocked_fops = {
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
+ .get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_unlocked_ioctl,
#ifdef CONFIG_COMPAT
@@ -303,6 +321,7 @@ static const struct file_operations v4l2_fops = {
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
+ .get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
@@ -404,12 +423,11 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
/* A minor value of -1 marks this video device as never
having been registered */
- if (vdev)
- vdev->minor = -1;
+ vdev->minor = -1;
/* the release callback MUST be present */
- WARN_ON(!vdev || !vdev->release);
- if (!vdev || !vdev->release)
+ WARN_ON(!vdev->release);
+ if (!vdev->release)
return -EINVAL;
/* Part 1: check device type */
@@ -434,7 +452,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
vdev->vfl_type = type;
vdev->cdev = NULL;
- if (vdev->v4l2_dev)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->dev)
vdev->parent = vdev->v4l2_dev->dev;
/* Part 2: find a free minor, kernel number and device index. */
@@ -655,6 +673,7 @@ module_exit(videodev_exit)
MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);
/*
diff --git a/linux/drivers/media/video/v4l2-device.c b/linux/drivers/media/video/v4l2-device.c
index 35e42e947..2cb81c210 100644
--- a/linux/drivers/media/video/v4l2-device.c
+++ b/linux/drivers/media/video/v4l2-device.c
@@ -50,19 +50,26 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
}
EXPORT_SYMBOL_GPL(v4l2_device_register);
+void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
+{
+ if (v4l2_dev->dev) {
+ dev_set_drvdata(v4l2_dev->dev, NULL);
+ v4l2_dev->dev = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
+
void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
{
struct v4l2_subdev *sd, *next;
if (v4l2_dev == NULL)
return;
- if (v4l2_dev->dev)
- dev_set_drvdata(v4l2_dev->dev, NULL);
+ v4l2_device_disconnect(v4l2_dev);
+
/* Unregister subdevs */
list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
v4l2_device_unregister_subdev(sd);
-
- v4l2_dev->dev = NULL;
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister);
diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c
index ec139df5c..c16ef96ee 100644
--- a/linux/drivers/media/video/v4l2-ioctl.c
+++ b/linux/drivers/media/video/v4l2-ioctl.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls */
+#include <linux/videodev.h>
#include <linux/videodev2.h>
#ifdef CONFIG_VIDEO_V4L1
@@ -25,7 +26,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
-#include <linux/video_decoder.h>
#include "compat.h"
#define dbgarg(cmd, fmt, arg...) \
@@ -102,25 +102,27 @@ const char *v4l2_norm_to_name(v4l2_std_id id)
}
EXPORT_SYMBOL(v4l2_norm_to_name);
+/* Returns frame period for the given standard */
+void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod)
+{
+ if (id & V4L2_STD_525_60) {
+ frameperiod->numerator = 1001;
+ frameperiod->denominator = 30000;
+ } else {
+ frameperiod->numerator = 1;
+ frameperiod->denominator = 25;
+ }
+}
+EXPORT_SYMBOL(v4l2_video_std_frame_period);
+
/* Fill in the fields of a v4l2_standard structure according to the
'id' and 'transmission' parameters. Returns negative on error. */
int v4l2_video_std_construct(struct v4l2_standard *vs,
int id, const char *name)
{
- u32 index = vs->index;
-
- memset(vs, 0, sizeof(struct v4l2_standard));
- vs->index = index;
- vs->id = id;
- if (id & V4L2_STD_525_60) {
- vs->frameperiod.numerator = 1001;
- vs->frameperiod.denominator = 30000;
- vs->framelines = 525;
- } else {
- vs->frameperiod.numerator = 1;
- vs->frameperiod.denominator = 25;
- vs->framelines = 625;
- }
+ vs->id = id;
+ v4l2_video_std_frame_period(id, &vs->frameperiod);
+ vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625;
strlcpy(vs->name, name, sizeof(vs->name));
return 0;
}
@@ -275,19 +277,6 @@ static const char *v4l2_ioctls[] = {
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
static const char *v4l2_int_ioctls[] = {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
- [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
- [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
- [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT",
- [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT",
- [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT",
- [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE",
- [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO",
- [_IOC_NR(DECODER_INIT)] = "DECODER_INIT",
- [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS",
- [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
-#endif
[_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
[_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
@@ -656,8 +645,6 @@ static long __video_do_ioctl(struct file *file,
if (cmd == VIDIOCGMBUF) {
struct video_mbuf *p = arg;
- memset(p, 0, sizeof(*p));
-
if (!ops->vidiocgmbuf)
return ret;
ret = ops->vidiocgmbuf(file, fh, p);
@@ -684,7 +671,6 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = (struct v4l2_capability *)arg;
- memset(cap, 0, sizeof(*cap));
if (!ops->vidioc_querycap)
break;
@@ -727,16 +713,8 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
-
- index = f->index;
- type = f->type;
- memset(f, 0, sizeof(*f));
- f->index = index;
- f->type = type;
- switch (type) {
+ switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (ops->vidioc_enum_fmt_vid_cap)
ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
@@ -773,8 +751,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_format *f = (struct v4l2_format *)arg;
- memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
-
/* FIXME: Should be one dump per type */
dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
@@ -1090,7 +1066,6 @@ static long __video_do_ioctl(struct file *file,
return -EINVAL;
v4l2_video_std_construct(p, curr_id, descr);
- p->index = index;
dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
"framelines=%d\n", p->index,
@@ -1155,12 +1130,9 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *p = arg;
- int i = p->index;
if (!ops->vidioc_enum_input)
break;
- memset(p, 0, sizeof(*p));
- p->index = i;
ret = ops->vidioc_enum_input(file, fh, p);
if (!ret)
@@ -1199,12 +1171,9 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_ENUMOUTPUT:
{
struct v4l2_output *p = arg;
- int i = p->index;
if (!ops->vidioc_enum_output)
break;
- memset(p, 0, sizeof(*p));
- p->index = i;
ret = ops->vidioc_enum_output(file, fh, p);
if (!ret)
@@ -1380,13 +1349,10 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_AUDIO:
{
struct v4l2_audio *p = arg;
- __u32 index = p->index;
if (!ops->vidioc_g_audio)
break;
- memset(p, 0, sizeof(*p));
- p->index = index;
ret = ops->vidioc_g_audio(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1428,7 +1394,7 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_audout)
break;
- dbgarg(cmd, "Enum for index=%d\n", p->index);
+
ret = ops->vidioc_g_audout(file, fh, p);
if (!ret)
dbgarg2("index=%d, name=%s, capability=%d, "
@@ -1481,15 +1447,10 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_CROP:
{
struct v4l2_crop *p = arg;
- __u32 type;
if (!ops->vidioc_g_crop)
break;
- type = p->type;
- memset(p, 0, sizeof(*p));
- p->type = type;
-
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret = ops->vidioc_g_crop(file, fh, p);
if (!ret)
@@ -1510,16 +1471,11 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *p = arg;
- __u32 type;
/*FIXME: Should also show v4l2_fract pixelaspect */
if (!ops->vidioc_cropcap)
break;
- type = p->type;
- memset(p, 0, sizeof(*p));
- p->type = type;
-
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret = ops->vidioc_cropcap(file, fh, p);
if (!ret) {
@@ -1535,8 +1491,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_jpegcomp)
break;
- memset(p, 0, sizeof(*p));
-
ret = ops->vidioc_g_jpegcomp(file, fh, p);
if (!ret)
dbgarg(cmd, "quality=%d, APPn=%d, "
@@ -1577,7 +1531,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_encoder_cmd)
break;
- memset(&p->raw, 0, sizeof(p->raw));
ret = ops->vidioc_encoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1589,7 +1542,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_try_encoder_cmd)
break;
- memset(&p->raw, 0, sizeof(p->raw));
ret = ops->vidioc_try_encoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1598,23 +1550,18 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_PARM:
{
struct v4l2_streamparm *p = arg;
- __u32 type = p->type;
-
- memset(p, 0, sizeof(*p));
- p->type = type;
if (ops->vidioc_g_parm) {
+ ret = check_fmt(ops, p->type);
+ if (ret)
+ break;
ret = ops->vidioc_g_parm(file, fh, p);
} else {
- struct v4l2_standard s;
-
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- v4l2_video_std_construct(&s, vfd->current_norm,
- v4l2_norm_to_name(vfd->current_norm));
-
- p->parm.capture.timeperframe = s.frameperiod;
+ v4l2_video_std_frame_period(vfd->current_norm,
+ &p->parm.capture.timeperframe);
ret = 0;
}
@@ -1627,6 +1574,10 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_s_parm)
break;
+ ret = check_fmt(ops, p->type);
+ if (ret)
+ break;
+
dbgarg(cmd, "type=%d\n", p->type);
ret = ops->vidioc_s_parm(file, fh, p);
break;
@@ -1634,14 +1585,10 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *p = arg;
- __u32 index = p->index;
if (!ops->vidioc_g_tuner)
break;
- memset(p, 0, sizeof(*p));
- p->index = index;
-
ret = ops->vidioc_g_tuner(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1678,8 +1625,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_frequency)
break;
- memset(p->reserved, 0, sizeof(p->reserved));
-
ret = ops->vidioc_g_frequency(file, fh, p);
if (!ret)
dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1700,12 +1645,13 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *p = arg;
- __u32 type = p->type;
if (!ops->vidioc_g_sliced_vbi_cap)
break;
- memset(p, 0, sizeof(*p));
- p->type = type;
+
+ /* Clear up to type, everything after type is zerod already */
+ memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
+
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p);
if (!ret)
@@ -1754,11 +1700,6 @@ static long __video_do_ioctl(struct file *file,
dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
break;
}
- case VIDIOC_G_CHIP_IDENT_OLD:
- printk(KERN_ERR "VIDIOC_G_CHIP_IDENT has been deprecated and will disappear in 2.6.30.\n");
- printk(KERN_ERR "It is a debugging ioctl and must not be used in applications!\n");
- return -EINVAL;
-
case VIDIOC_S_HW_FREQ_SEEK:
{
struct v4l2_hw_freq_seek *p = arg;
@@ -1778,8 +1719,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_enum_framesizes)
break;
- memset(p, 0, sizeof(*p));
-
ret = ops->vidioc_enum_framesizes(file, fh, p);
dbgarg(cmd,
"index=%d, pixelformat=%d, type=%d ",
@@ -1811,8 +1750,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_enum_frameintervals)
break;
- memset(p, 0, sizeof(*p));
-
ret = ops->vidioc_enum_frameintervals(file, fh, p);
dbgarg(cmd,
"index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
@@ -1861,6 +1798,45 @@ static long __video_do_ioctl(struct file *file,
return ret;
}
+/* In some cases, only a few fields are used as input, i.e. when the app sets
+ * "index" and then the driver fills in the rest of the structure for the thing
+ * with that index. We only need to copy up the first non-input field. */
+static unsigned long cmd_input_size(unsigned int cmd)
+{
+ /* Size of structure up to and including 'field' */
+#define CMDINSIZE(cmd, type, field) \
+ case VIDIOC_##cmd: \
+ return offsetof(struct v4l2_##type, field) + \
+ sizeof(((struct v4l2_##type *)0)->field);
+
+ switch (cmd) {
+ CMDINSIZE(ENUM_FMT, fmtdesc, type);
+ CMDINSIZE(G_FMT, format, type);
+ CMDINSIZE(QUERYBUF, buffer, type);
+ CMDINSIZE(G_PARM, streamparm, type);
+ CMDINSIZE(ENUMSTD, standard, index);
+ CMDINSIZE(ENUMINPUT, input, index);
+ CMDINSIZE(G_CTRL, control, id);
+ CMDINSIZE(G_TUNER, tuner, index);
+ CMDINSIZE(QUERYCTRL, queryctrl, id);
+ CMDINSIZE(QUERYMENU, querymenu, index);
+ CMDINSIZE(ENUMOUTPUT, output, index);
+ CMDINSIZE(G_MODULATOR, modulator, index);
+ CMDINSIZE(G_FREQUENCY, frequency, tuner);
+ CMDINSIZE(CROPCAP, cropcap, type);
+ CMDINSIZE(G_CROP, crop, type);
+ CMDINSIZE(ENUMAUDIO, audio, index);
+ CMDINSIZE(ENUMAUDOUT, audioout, index);
+ CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
+ CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
+ CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
+ CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
+ CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
+ default:
+ return _IOC_SIZE(cmd);
+ }
+}
+
long video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1879,13 +1855,7 @@ long video_ioctl2(struct file *file,
cmd == VIDIOC_TRY_EXT_CTRLS);
/* Copy arguments into temp kernel buffer */
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE:
- parg = NULL;
- break;
- case _IOC_READ:
- case _IOC_WRITE:
- case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_DIR(cmd) != _IOC_NONE) {
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
@@ -1897,10 +1867,19 @@ long video_ioctl2(struct file *file,
}
err = -EFAULT;
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ unsigned long n = cmd_input_size(cmd);
+
+ if (copy_from_user(parg, (void __user *)arg, n))
goto out;
- break;
+
+ /* zero out anything we don't copy from userspace */
+ if (n < _IOC_SIZE(cmd))
+ memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+ } else {
+ /* read-only ioctl */
+ memset(parg, 0, _IOC_SIZE(cmd));
+ }
}
if (is_ext_ctrl) {
diff --git a/linux/drivers/media/video/v4l2-subdev.c b/linux/drivers/media/video/v4l2-subdev.c
index 923ec8d01..dc881671d 100644
--- a/linux/drivers/media/video/v4l2-subdev.c
+++ b/linux/drivers/media/video/v4l2-subdev.c
@@ -98,6 +98,10 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
return v4l2_subdev_call(sd, video, g_vbi_data, arg);
case VIDIOC_G_SLICED_VBI_CAP:
return v4l2_subdev_call(sd, video, g_sliced_vbi_cap, arg);
+ case VIDIOC_ENUM_FMT:
+ return v4l2_subdev_call(sd, video, enum_fmt, arg);
+ case VIDIOC_TRY_FMT:
+ return v4l2_subdev_call(sd, video, try_fmt, arg);
case VIDIOC_S_FMT:
return v4l2_subdev_call(sd, video, s_fmt, arg);
case VIDIOC_G_FMT:
@@ -112,6 +116,10 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
return v4l2_subdev_call(sd, video, s_stream, 1);
case VIDIOC_STREAMOFF:
return v4l2_subdev_call(sd, video, s_stream, 0);
+ case VIDIOC_S_PARM:
+ return v4l2_subdev_call(sd, video, s_parm, arg);
+ case VIDIOC_G_PARM:
+ return v4l2_subdev_call(sd, video, g_parm, arg);
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c
index 349ef053f..274b99b56 100644
--- a/linux/drivers/media/video/vino.c
+++ b/linux/drivers/media/video/vino.c
@@ -8,6 +8,12 @@
*
* Based on the previous version of the driver for 2.4 kernels by:
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this conversion is untested! Please contact the linux-media
+ * mailinglist if you can test this, together with the test results.
*/
/*
@@ -33,12 +39,10 @@
#include <linux/kmod.h>
#include <linux/i2c.h>
-#include <linux/i2c-algo-sgi.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <linux/video_decoder.h>
#include <linux/mutex.h>
#include <asm/paccess.h>
@@ -139,13 +143,23 @@ MODULE_LICENSE("GPL");
#define VINO_DATA_NORM_PAL 1
#define VINO_DATA_NORM_SECAM 2
#define VINO_DATA_NORM_D1 3
-/* The following are special entries that can be used to
- * autodetect the norm. */
-#define VINO_DATA_NORM_AUTO 0xfe
-#define VINO_DATA_NORM_AUTO_EXT 0xff
#define VINO_DATA_NORM_COUNT 4
+/* I2C controller flags */
+#define SGI_I2C_FORCE_IDLE (0 << 0)
+#define SGI_I2C_NOT_IDLE (1 << 0)
+#define SGI_I2C_WRITE (0 << 1)
+#define SGI_I2C_READ (1 << 1)
+#define SGI_I2C_RELEASE_BUS (0 << 2)
+#define SGI_I2C_HOLD_BUS (1 << 2)
+#define SGI_I2C_XFER_DONE (0 << 4)
+#define SGI_I2C_XFER_BUSY (1 << 4)
+#define SGI_I2C_ACK (0 << 5)
+#define SGI_I2C_NACK (1 << 5)
+#define SGI_I2C_BUS_OK (0 << 7)
+#define SGI_I2C_BUS_ERR (1 << 7)
+
/* Internal data structure definitions */
struct vino_input {
@@ -289,22 +303,20 @@ struct vino_channel_settings {
struct vino_interrupt_data int_data;
/* V4L support */
- struct video_device *v4l_device;
-};
-
-struct vino_client {
- /* the channel which owns this client:
- * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
- unsigned int owner;
- struct i2c_client *driver;
+ struct video_device *vdev;
};
struct vino_settings {
+ struct v4l2_device v4l2_dev;
struct vino_channel_settings a;
struct vino_channel_settings b;
- struct vino_client decoder;
- struct vino_client camera;
+ /* the channel which owns this client:
+ * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+ unsigned int decoder_owner;
+ struct v4l2_subdev *decoder;
+ unsigned int camera_owner;
+ struct v4l2_subdev *camera;
/* a lock for vino register access */
spinlock_t vino_lock;
@@ -344,11 +356,16 @@ static struct sgi_vino *vino;
static struct vino_settings *vino_drvdata;
+#define camera_call(o, f, args...) \
+ v4l2_subdev_call(vino_drvdata->camera, o, f, ##args)
+#define decoder_call(o, f, args...) \
+ v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args)
+
static const char *vino_driver_name = "vino";
static const char *vino_driver_description = "SGI VINO";
static const char *vino_bus_name = "GIO64 bus";
-static const char *vino_v4l_device_name_a = "SGI VINO Channel A";
-static const char *vino_v4l_device_name_b = "SGI VINO Channel B";
+static const char *vino_vdev_name_a = "SGI VINO Channel A";
+static const char *vino_vdev_name_b = "SGI VINO Channel B";
static void vino_capture_tasklet(unsigned long channel);
@@ -360,11 +377,11 @@ static const struct vino_input vino_inputs[] = {
.name = "Composite",
.std = V4L2_STD_NTSC | V4L2_STD_PAL
| V4L2_STD_SECAM,
- },{
+ }, {
.name = "S-Video",
.std = V4L2_STD_NTSC | V4L2_STD_PAL
| V4L2_STD_SECAM,
- },{
+ }, {
.name = "D1/IndyCam",
.std = V4L2_STD_NTSC,
}
@@ -376,17 +393,17 @@ static const struct vino_data_format vino_data_formats[] = {
.bpp = 1,
.pixelformat = V4L2_PIX_FMT_GREY,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
- },{
+ }, {
.description = "8-bit dithered RGB 3-3-2",
.bpp = 1,
.pixelformat = V4L2_PIX_FMT_RGB332,
.colorspace = V4L2_COLORSPACE_SRGB,
- },{
+ }, {
.description = "32-bit RGB",
.bpp = 4,
.pixelformat = V4L2_PIX_FMT_RGB32,
.colorspace = V4L2_COLORSPACE_SRGB,
- },{
+ }, {
.description = "YUV 4:2:2",
.bpp = 2,
.pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped?
@@ -417,7 +434,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ VINO_NTSC_HEIGHT / 2 - 1,
.right = VINO_NTSC_WIDTH,
},
- },{
+ }, {
.description = "PAL",
.std = V4L2_STD_PAL,
.fps_min = 5,
@@ -439,7 +456,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ VINO_PAL_HEIGHT / 2 - 1,
.right = VINO_PAL_WIDTH,
},
- },{
+ }, {
.description = "SECAM",
.std = V4L2_STD_SECAM,
.fps_min = 5,
@@ -461,7 +478,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ VINO_PAL_HEIGHT / 2 - 1,
.right = VINO_PAL_WIDTH,
},
- },{
+ }, {
.description = "NTSC/D1",
.std = V4L2_STD_NTSC,
.fps_min = 6,
@@ -497,9 +514,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = 1,
.step = 1,
.default_value = INDYCAM_AGC_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_AGC, 0 },
- },{
+ }, {
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Automatic White Balance",
@@ -507,9 +522,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = 1,
.step = 1,
.default_value = INDYCAM_AWB_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_AWB, 0 },
- },{
+ }, {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
@@ -517,29 +530,23 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_GAIN_MAX,
.step = 1,
.default_value = INDYCAM_GAIN_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_GAIN, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE,
+ }, {
+ .id = INDYCAM_CONTROL_RED_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Red Saturation",
.minimum = INDYCAM_RED_SATURATION_MIN,
.maximum = INDYCAM_RED_SATURATION_MAX,
.step = 1,
.default_value = INDYCAM_RED_SATURATION_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_RED_SATURATION, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 1,
+ }, {
+ .id = INDYCAM_CONTROL_BLUE_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Blue Saturation",
.minimum = INDYCAM_BLUE_SATURATION_MIN,
.maximum = INDYCAM_BLUE_SATURATION_MAX,
.step = 1,
.default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_BLUE_SATURATION, 0 },
- },{
+ }, {
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Red Balance",
@@ -547,9 +554,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_RED_BALANCE_MAX,
.step = 1,
.default_value = INDYCAM_RED_BALANCE_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_RED_BALANCE, 0 },
- },{
+ }, {
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Blue Balance",
@@ -557,9 +562,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_BLUE_BALANCE_MAX,
.step = 1,
.default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_BLUE_BALANCE, 0 },
- },{
+ }, {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Shutter Control",
@@ -567,9 +570,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_SHUTTER_MAX,
.step = 1,
.default_value = INDYCAM_SHUTTER_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_SHUTTER, 0 },
- },{
+ }, {
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gamma",
@@ -577,8 +578,6 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_GAMMA_MAX,
.step = 1,
.default_value = INDYCAM_GAMMA_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_GAMMA, 0 },
}
};
@@ -593,209 +592,73 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
.maximum = SAA7191_HUE_MAX,
.step = 1,
.default_value = SAA7191_HUE_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_HUE, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE,
+ }, {
+ .id = SAA7191_CONTROL_BANDPASS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Luminance Bandpass",
.minimum = SAA7191_BANDPASS_MIN,
.maximum = SAA7191_BANDPASS_MAX,
.step = 1,
.default_value = SAA7191_BANDPASS_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_BANDPASS, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 1,
+ }, {
+ .id = SAA7191_CONTROL_BANDPASS_WEIGHT,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Luminance Bandpass Weight",
.minimum = SAA7191_BANDPASS_WEIGHT_MIN,
.maximum = SAA7191_BANDPASS_WEIGHT_MAX,
.step = 1,
.default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_BANDPASS_WEIGHT, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 2,
+ }, {
+ .id = SAA7191_CONTROL_CORING,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "HF Luminance Coring",
.minimum = SAA7191_CORING_MIN,
.maximum = SAA7191_CORING_MAX,
.step = 1,
.default_value = SAA7191_CORING_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_CORING, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 3,
+ }, {
+ .id = SAA7191_CONTROL_FORCE_COLOUR,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Force Colour",
.minimum = SAA7191_FORCE_COLOUR_MIN,
.maximum = SAA7191_FORCE_COLOUR_MAX,
.step = 1,
.default_value = SAA7191_FORCE_COLOUR_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_FORCE_COLOUR, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 4,
+ }, {
+ .id = SAA7191_CONTROL_CHROMA_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Chrominance Gain Control",
.minimum = SAA7191_CHROMA_GAIN_MIN,
.maximum = SAA7191_CHROMA_GAIN_MAX,
.step = 1,
.default_value = SAA7191_CHROMA_GAIN_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_CHROMA_GAIN, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 5,
+ }, {
+ .id = SAA7191_CONTROL_VTRC,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "VTR Time Constant",
.minimum = SAA7191_VTRC_MIN,
.maximum = SAA7191_VTRC_MAX,
.step = 1,
.default_value = SAA7191_VTRC_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_VTRC, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 6,
+ }, {
+ .id = SAA7191_CONTROL_LUMA_DELAY,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Luminance Delay Compensation",
.minimum = SAA7191_LUMA_DELAY_MIN,
.maximum = SAA7191_LUMA_DELAY_MAX,
.step = 1,
.default_value = SAA7191_LUMA_DELAY_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_LUMA_DELAY, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 7,
+ }, {
+ .id = SAA7191_CONTROL_VNR,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Vertical Noise Reduction",
.minimum = SAA7191_VNR_MIN,
.maximum = SAA7191_VNR_MAX,
.step = 1,
.default_value = SAA7191_VNR_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_VNR, 0 },
}
};
-/* VINO I2C bus functions */
-
-unsigned i2c_vino_getctrl(void *data)
-{
- return vino->i2c_control;
-}
-
-void i2c_vino_setctrl(void *data, unsigned val)
-{
- vino->i2c_control = val;
-}
-
-unsigned i2c_vino_rdata(void *data)
-{
- return vino->i2c_data;
-}
-
-void i2c_vino_wdata(void *data, unsigned val)
-{
- vino->i2c_data = val;
-}
-
-static struct i2c_algo_sgi_data i2c_sgi_vino_data =
-{
- .getctrl = &i2c_vino_getctrl,
- .setctrl = &i2c_vino_setctrl,
- .rdata = &i2c_vino_rdata,
- .wdata = &i2c_vino_wdata,
- .xfer_timeout = 200,
- .ack_timeout = 1000,
-};
-
-/*
- * There are two possible clients on VINO I2C bus, so we limit usage only
- * to them.
- */
-static int i2c_vino_client_reg(struct i2c_client *client)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- switch (client->driver->id) {
- case I2C_DRIVERID_SAA7191:
- if (vino_drvdata->decoder.driver)
- ret = -EBUSY;
- else
- vino_drvdata->decoder.driver = client;
- break;
- case I2C_DRIVERID_INDYCAM:
- if (vino_drvdata->camera.driver)
- ret = -EBUSY;
- else
- vino_drvdata->camera.driver = client;
- break;
- default:
- ret = -ENODEV;
- }
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return ret;
-}
-
-static int i2c_vino_client_unreg(struct i2c_client *client)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- if (client == vino_drvdata->decoder.driver) {
- if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
- ret = -EBUSY;
- else
- vino_drvdata->decoder.driver = NULL;
- } else if (client == vino_drvdata->camera.driver) {
- if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)
- ret = -EBUSY;
- else
- vino_drvdata->camera.driver = NULL;
- }
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return ret;
-}
-
-static struct i2c_adapter vino_i2c_adapter =
-{
- .name = "VINO I2C bus",
- .id = I2C_HW_SGI_VINO,
- .algo_data = &i2c_sgi_vino_data,
- .client_register = &i2c_vino_client_reg,
- .client_unregister = &i2c_vino_client_unreg,
-};
-
-static int vino_i2c_add_bus(void)
-{
- return i2c_sgi_add_bus(&vino_i2c_adapter);
-}
-
-static int vino_i2c_del_bus(void)
-{
- return i2c_del_adapter(&vino_i2c_adapter);
-}
-
-static int i2c_camera_command(unsigned int cmd, void *arg)
-{
- return vino_drvdata->camera.driver->
- driver->command(vino_drvdata->camera.driver,
- cmd, arg);
-}
-
-static int i2c_decoder_command(unsigned int cmd, void *arg)
-{
- return vino_drvdata->decoder.driver->
- driver->command(vino_drvdata->decoder.driver,
- cmd, arg);
-}
-
/* VINO framebuffer/DMA descriptor management */
static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
@@ -1741,6 +1604,184 @@ static inline void vino_set_default_framerate(struct
vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
}
+/* VINO I2C bus functions */
+
+struct i2c_algo_sgi_data {
+ void *data; /* private data for lowlevel routines */
+ unsigned (*getctrl)(void *data);
+ void (*setctrl)(void *data, unsigned val);
+ unsigned (*rdata)(void *data);
+ void (*wdata)(void *data, unsigned val);
+
+ int xfer_timeout;
+ int ack_timeout;
+};
+
+static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int wait_ack(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ if (wait_xfer_done(adap))
+ return -ETIMEDOUT;
+ for (i = 0; i < adap->ack_timeout; i++) {
+ if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int force_idle(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE);
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0)
+ goto out;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+out:
+ if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR)
+ return -EIO;
+ return 0;
+}
+
+static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
+ int rd)
+{
+ if (rd)
+ adap->setctrl(adap->data, SGI_I2C_NOT_IDLE);
+ /* Check if bus is idle, eventually force it to do so */
+ if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE)
+ if (force_idle(adap))
+ return -EIO;
+ /* Write out the i2c chip address and specify operation */
+ adap->setctrl(adap->data,
+ SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
+ if (rd)
+ addr |= 1;
+ adap->wdata(adap->data, addr);
+ if (wait_ack(adap))
+ return -EIO;
+ return 0;
+}
+
+static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+
+ adap->setctrl(adap->data,
+ SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
+ for (i = 0; i < len; i++) {
+ if (wait_xfer_done(adap))
+ return -EIO;
+ buf[i] = adap->rdata(adap->data);
+ }
+ adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
+
+ return 0;
+
+}
+
+static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+
+ /* We are already in write state */
+ for (i = 0; i < len; i++) {
+ adap->wdata(adap->data, buf[i]);
+ if (wait_ack(adap))
+ return -EIO;
+ }
+ return 0;
+}
+
+static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *p;
+ int i, err = 0;
+
+ for (i = 0; !err && i < num; i++) {
+ p = &msgs[i];
+ err = do_address(adap, p->addr, p->flags & I2C_M_RD);
+ if (err || !p->len)
+ continue;
+ if (p->flags & I2C_M_RD)
+ err = i2c_read(adap, p->buf, p->len);
+ else
+ err = i2c_write(adap, p->buf, p->len);
+ }
+
+ return (err < 0) ? err : i;
+}
+
+static u32 sgi_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm sgi_algo = {
+ .master_xfer = sgi_xfer,
+ .functionality = sgi_func,
+};
+
+static unsigned i2c_vino_getctrl(void *data)
+{
+ return vino->i2c_control;
+}
+
+static void i2c_vino_setctrl(void *data, unsigned val)
+{
+ vino->i2c_control = val;
+}
+
+static unsigned i2c_vino_rdata(void *data)
+{
+ return vino->i2c_data;
+}
+
+static void i2c_vino_wdata(void *data, unsigned val)
+{
+ vino->i2c_data = val;
+}
+
+static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
+ .getctrl = &i2c_vino_getctrl,
+ .setctrl = &i2c_vino_setctrl,
+ .rdata = &i2c_vino_rdata,
+ .wdata = &i2c_vino_wdata,
+ .xfer_timeout = 200,
+ .ack_timeout = 1000,
+};
+
+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,
+};
+
/*
* Prepare VINO for DMA transfer...
* (execute only with vino_lock and input_lock locked)
@@ -2494,86 +2535,15 @@ static int vino_get_saa7191_input(int input)
}
}
-static int vino_get_saa7191_norm(unsigned int data_norm)
-{
- switch (data_norm) {
- case VINO_DATA_NORM_AUTO:
- return SAA7191_NORM_AUTO;
- case VINO_DATA_NORM_AUTO_EXT:
- return SAA7191_NORM_AUTO_EXT;
- case VINO_DATA_NORM_PAL:
- return SAA7191_NORM_PAL;
- case VINO_DATA_NORM_NTSC:
- return SAA7191_NORM_NTSC;
- case VINO_DATA_NORM_SECAM:
- return SAA7191_NORM_SECAM;
- default:
- printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "
- "invalid norm!\n");
- return -1;
- }
-}
-
-static int vino_get_from_saa7191_norm(int saa7191_norm)
-{
- switch (saa7191_norm) {
- case SAA7191_NORM_PAL:
- return VINO_DATA_NORM_PAL;
- case SAA7191_NORM_NTSC:
- return VINO_DATA_NORM_NTSC;
- case SAA7191_NORM_SECAM:
- return VINO_DATA_NORM_SECAM;
- default:
- printk(KERN_ERR "VINO: vino_get_from_saa7191_norm(): "
- "invalid norm!\n");
- return VINO_DATA_NORM_NONE;
- }
-}
-
-static int vino_saa7191_set_norm(unsigned int *data_norm)
-{
- int saa7191_norm, new_data_norm;
- int err = 0;
-
- saa7191_norm = vino_get_saa7191_norm(*data_norm);
-
- err = i2c_decoder_command(DECODER_SAA7191_SET_NORM,
- &saa7191_norm);
- if (err)
- goto out;
-
- if ((*data_norm == VINO_DATA_NORM_AUTO)
- || (*data_norm == VINO_DATA_NORM_AUTO_EXT)) {
- struct saa7191_status status;
-
- err = i2c_decoder_command(DECODER_SAA7191_GET_STATUS,
- &status);
- if (err)
- goto out;
-
- new_data_norm =
- vino_get_from_saa7191_norm(status.norm);
- if (new_data_norm == VINO_DATA_NORM_NONE) {
- err = -EINVAL;
- goto out;
- }
-
- *data_norm = (unsigned int)new_data_norm;
- }
-
-out:
- return err;
-}
-
/* execute with input_lock locked */
static int vino_is_input_owner(struct vino_channel_settings *vcs)
{
switch(vcs->input) {
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO:
- return (vino_drvdata->decoder.owner == vcs->channel);
+ return vino_drvdata->decoder_owner == vcs->channel;
case VINO_INPUT_D1:
- return (vino_drvdata->camera.owner == vcs->channel);
+ return vino_drvdata->camera_owner == vcs->channel;
default:
return 0;
}
@@ -2589,23 +2559,22 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
/* First try D1 and then SAA7191 */
- if (vino_drvdata->camera.driver
- && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
- i2c_use_client(vino_drvdata->camera.driver);
- vino_drvdata->camera.owner = vcs->channel;
+ if (vino_drvdata->camera
+ && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) {
+ vino_drvdata->camera_owner = vcs->channel;
vcs->input = VINO_INPUT_D1;
vcs->data_norm = VINO_DATA_NORM_D1;
- } else if (vino_drvdata->decoder.driver
- && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {
- int input, data_norm;
- int saa7191_input;
+ } else if (vino_drvdata->decoder
+ && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) {
+ int input;
+ int data_norm;
+ v4l2_std_id norm;
+ struct v4l2_routing route = { 0, 0 };
- i2c_use_client(vino_drvdata->decoder.driver);
input = VINO_INPUT_COMPOSITE;
- saa7191_input = vino_get_saa7191_input(input);
- ret = i2c_decoder_command(DECODER_SET_INPUT,
- &saa7191_input);
+ route.input = vino_get_saa7191_input(input);
+ ret = decoder_call(video, s_routing, &route);
if (ret) {
ret = -EINVAL;
goto out;
@@ -2616,12 +2585,15 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
/* Don't hold spinlocks while auto-detecting norm
* as it may take a while... */
- data_norm = VINO_DATA_NORM_AUTO_EXT;
-
- ret = vino_saa7191_set_norm(&data_norm);
- if ((ret == -EBUSY) || (ret == -EAGAIN)) {
- data_norm = VINO_DATA_NORM_PAL;
- ret = vino_saa7191_set_norm(&data_norm);
+ ret = decoder_call(video, querystd, &norm);
+ if (!ret) {
+ for (data_norm = 0; data_norm < 3; data_norm++) {
+ if (vino_data_norms[data_norm].std & norm)
+ break;
+ }
+ if (data_norm == 3)
+ data_norm = VINO_DATA_NORM_PAL;
+ ret = decoder_call(tuner, s_std, norm);
}
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -2631,7 +2603,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
goto out;
}
- vino_drvdata->decoder.owner = vcs->channel;
+ vino_drvdata->decoder_owner = vcs->channel;
vcs->input = input;
vcs->data_norm = data_norm;
@@ -2676,25 +2648,24 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
switch (input) {
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO:
- if (!vino_drvdata->decoder.driver) {
+ if (!vino_drvdata->decoder) {
ret = -EINVAL;
goto out;
}
- if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
- i2c_use_client(vino_drvdata->decoder.driver);
- vino_drvdata->decoder.owner = vcs->channel;
+ if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) {
+ vino_drvdata->decoder_owner = vcs->channel;
}
- if (vino_drvdata->decoder.owner == vcs->channel) {
+ if (vino_drvdata->decoder_owner == vcs->channel) {
int data_norm;
- int saa7191_input;
+ v4l2_std_id norm;
+ struct v4l2_routing route = { 0, 0 };
- saa7191_input = vino_get_saa7191_input(input);
- ret = i2c_decoder_command(DECODER_SET_INPUT,
- &saa7191_input);
+ route.input = vino_get_saa7191_input(input);
+ ret = decoder_call(video, s_routing, &route);
if (ret) {
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
ret = -EINVAL;
goto out;
}
@@ -2704,18 +2675,21 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
/* Don't hold spinlocks while auto-detecting norm
* as it may take a while... */
- data_norm = VINO_DATA_NORM_AUTO_EXT;
-
- ret = vino_saa7191_set_norm(&data_norm);
- if ((ret == -EBUSY) || (ret == -EAGAIN)) {
- data_norm = VINO_DATA_NORM_PAL;
- ret = vino_saa7191_set_norm(&data_norm);
+ ret = decoder_call(video, querystd, &norm);
+ if (!ret) {
+ for (data_norm = 0; data_norm < 3; data_norm++) {
+ if (vino_data_norms[data_norm].std & norm)
+ break;
+ }
+ if (data_norm == 3)
+ data_norm = VINO_DATA_NORM_PAL;
+ ret = decoder_call(tuner, s_std, norm);
}
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
if (ret) {
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
ret = -EINVAL;
goto out;
}
@@ -2732,37 +2706,31 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
vcs->data_norm = vcs2->data_norm;
}
- if (vino_drvdata->camera.owner == vcs->channel) {
+ if (vino_drvdata->camera_owner == vcs->channel) {
/* Transfer the ownership or release the input */
if (vcs2->input == VINO_INPUT_D1) {
- vino_drvdata->camera.owner = vcs2->channel;
+ vino_drvdata->camera_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->
- camera.driver);
- vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ vino_drvdata->camera_owner = VINO_NO_CHANNEL;
}
}
break;
case VINO_INPUT_D1:
- if (!vino_drvdata->camera.driver) {
+ if (!vino_drvdata->camera) {
ret = -EINVAL;
goto out;
}
- if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
- i2c_use_client(vino_drvdata->camera.driver);
- vino_drvdata->camera.owner = vcs->channel;
- }
+ if (vino_drvdata->camera_owner == VINO_NO_CHANNEL)
+ vino_drvdata->camera_owner = vcs->channel;
- if (vino_drvdata->decoder.owner == vcs->channel) {
+ if (vino_drvdata->decoder_owner == vcs->channel) {
/* Transfer the ownership or release the input */
if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
(vcs2->input == VINO_INPUT_SVIDEO)) {
- vino_drvdata->decoder.owner = vcs2->channel;
+ vino_drvdata->decoder_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->
- decoder.driver);
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
}
}
@@ -2799,20 +2767,18 @@ static void vino_release_input(struct vino_channel_settings *vcs)
/* Release ownership of the channel
* and if the other channel takes input from
* the same source, transfer the ownership */
- if (vino_drvdata->camera.owner == vcs->channel) {
+ if (vino_drvdata->camera_owner == vcs->channel) {
if (vcs2->input == VINO_INPUT_D1) {
- vino_drvdata->camera.owner = vcs2->channel;
+ vino_drvdata->camera_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->camera.driver);
- vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ vino_drvdata->camera_owner = VINO_NO_CHANNEL;
}
- } else if (vino_drvdata->decoder.owner == vcs->channel) {
+ } else if (vino_drvdata->decoder_owner == vcs->channel) {
if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
(vcs2->input == VINO_INPUT_SVIDEO)) {
- vino_drvdata->decoder.owner = vcs2->channel;
+ vino_drvdata->decoder_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->decoder.driver);
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
}
}
vcs->input = VINO_INPUT_NONE;
@@ -2833,18 +2799,16 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
switch (vcs->input) {
case VINO_INPUT_D1:
/* only one "norm" supported */
- if ((data_norm != VINO_DATA_NORM_D1)
- && (data_norm != VINO_DATA_NORM_AUTO)
- && (data_norm != VINO_DATA_NORM_AUTO_EXT))
+ if (data_norm != VINO_DATA_NORM_D1)
return -EINVAL;
break;
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO: {
+ v4l2_std_id norm;
+
if ((data_norm != VINO_DATA_NORM_PAL)
&& (data_norm != VINO_DATA_NORM_NTSC)
- && (data_norm != VINO_DATA_NORM_SECAM)
- && (data_norm != VINO_DATA_NORM_AUTO)
- && (data_norm != VINO_DATA_NORM_AUTO_EXT))
+ && (data_norm != VINO_DATA_NORM_SECAM))
return -EINVAL;
spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags);
@@ -2852,7 +2816,8 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
/* Don't hold spinlocks while setting norm
* as it may take a while... */
- err = vino_saa7191_set_norm(&data_norm);
+ norm = vino_data_norms[data_norm].std;
+ err = decoder_call(tuner, s_std, norm);
spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
@@ -2888,41 +2853,13 @@ static int vino_find_data_format(__u32 pixelformat)
return VINO_DATA_FMT_NONE;
}
-static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
-{
- int data_norm = VINO_DATA_NORM_NONE;
- unsigned long flags;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- switch(vcs->input) {
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
- if (index == 0) {
- data_norm = VINO_DATA_NORM_PAL;
- } else if (index == 1) {
- data_norm = VINO_DATA_NORM_NTSC;
- } else if (index == 2) {
- data_norm = VINO_DATA_NORM_SECAM;
- }
- break;
- case VINO_INPUT_D1:
- if (index == 0) {
- data_norm = VINO_DATA_NORM_D1;
- }
- break;
- }
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return data_norm;
-}
-
-static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index)
{
int input = VINO_INPUT_NONE;
unsigned long flags;
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ if (vino_drvdata->decoder && vino_drvdata->camera) {
switch (index) {
case 0:
input = VINO_INPUT_COMPOSITE;
@@ -2934,7 +2871,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
input = VINO_INPUT_D1;
break;
}
- } else if (vino_drvdata->decoder.driver) {
+ } else if (vino_drvdata->decoder) {
switch (index) {
case 0:
input = VINO_INPUT_COMPOSITE;
@@ -2943,7 +2880,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
input = VINO_INPUT_SVIDEO;
break;
}
- } else if (vino_drvdata->camera.driver) {
+ } else if (vino_drvdata->camera) {
switch (index) {
case 0:
input = VINO_INPUT_D1;
@@ -2961,7 +2898,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
__u32 index = 0;
// FIXME: detect when no inputs available
- if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ if (vino_drvdata->decoder && vino_drvdata->camera) {
switch (vcs->input) {
case VINO_INPUT_COMPOSITE:
index = 0;
@@ -2973,7 +2910,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
index = 2;
break;
}
- } else if (vino_drvdata->decoder.driver) {
+ } else if (vino_drvdata->decoder) {
switch (vcs->input) {
case VINO_INPUT_COMPOSITE:
index = 0;
@@ -2982,7 +2919,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
index = 1;
break;
}
- } else if (vino_drvdata->camera.driver) {
+ } else if (vino_drvdata->camera) {
switch (vcs->input) {
case VINO_INPUT_D1:
index = 0;
@@ -2995,7 +2932,8 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
/* V4L2 ioctls */
-static void vino_v4l2_querycap(struct v4l2_capability *cap)
+static int vino_querycap(struct file *file, void *__fh,
+ struct v4l2_capability *cap)
{
memset(cap, 0, sizeof(struct v4l2_capability));
@@ -3007,16 +2945,18 @@ static void vino_v4l2_querycap(struct v4l2_capability *cap)
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING;
// V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+ return 0;
}
-static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
+static int vino_enum_input(struct file *file, void *__fh,
struct v4l2_input *i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
__u32 index = i->index;
int input;
dprintk("requested index = %d\n", index);
- input = vino_enum_input(vcs, index);
+ input = vino_int_enum_input(vcs, index);
if (input == VINO_INPUT_NONE)
return -EINVAL;
@@ -3027,20 +2967,15 @@ static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
i->std = vino_inputs[input].std;
strcpy(i->name, vino_inputs[input].name);
- if ((input == VINO_INPUT_COMPOSITE)
- || (input == VINO_INPUT_SVIDEO)) {
- struct saa7191_status status;
- i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
- i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL;
- i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR;
- }
-
+ if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO)
+ decoder_call(video, g_input_status, &i->status);
return 0;
}
-static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
+static int vino_g_input(struct file *file, void *__fh,
unsigned int *i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
__u32 index;
int input;
unsigned long flags;
@@ -3061,52 +2996,24 @@ static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
- unsigned int *i)
+static int vino_s_input(struct file *file, void *__fh,
+ unsigned int i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
int input;
- dprintk("requested input = %d\n", *i);
+ dprintk("requested input = %d\n", i);
- input = vino_enum_input(vcs, *i);
+ input = vino_int_enum_input(vcs, i);
if (input == VINO_INPUT_NONE)
return -EINVAL;
return vino_set_input(vcs, input);
}
-static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
- struct v4l2_standard *s)
-{
- int index = s->index;
- int data_norm;
-
- data_norm = vino_enum_data_norm(vcs, index);
- dprintk("standard index = %d\n", index);
-
- if (data_norm == VINO_DATA_NORM_NONE)
- return -EINVAL;
-
- dprintk("standard name = %s\n",
- vino_data_norms[data_norm].description);
-
- memset(s, 0, sizeof(struct v4l2_standard));
- s->index = index;
-
- s->id = vino_data_norms[data_norm].std;
- s->frameperiod.numerator = 1;
- s->frameperiod.denominator =
- vino_data_norms[data_norm].fps_max;
- s->framelines =
- vino_data_norms[data_norm].framelines;
- strcpy(s->name,
- vino_data_norms[data_norm].description);
-
- return 0;
-}
-
-static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
+static int vino_querystd(struct file *file, void *__fh,
v4l2_std_id *std)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int err = 0;
@@ -3118,19 +3025,7 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
break;
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO: {
- struct saa7191_status status;
-
- i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
-
- if (status.signal) {
- if (status.signal_60hz) {
- *std = V4L2_STD_NTSC;
- } else {
- *std = V4L2_STD_PAL | V4L2_STD_SECAM;
- }
- } else {
- *std = vino_inputs[vcs->input].std;
- }
+ decoder_call(video, querystd, std);
break;
}
default:
@@ -3142,9 +3037,10 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
return err;
}
-static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
+static int vino_g_std(struct file *file, void *__fh,
v4l2_std_id *std)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -3157,9 +3053,10 @@ static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
+static int vino_s_std(struct file *file, void *__fh,
v4l2_std_id *std)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int ret = 0;
@@ -3180,12 +3077,7 @@ static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
if (vcs->input == VINO_INPUT_D1)
goto out;
- if (((*std) & V4L2_STD_PAL)
- && ((*std) & V4L2_STD_NTSC)
- && ((*std) & V4L2_STD_SECAM)) {
- ret = vino_set_data_norm(vcs, VINO_DATA_NORM_AUTO_EXT,
- &flags);
- } else if ((*std) & V4L2_STD_PAL) {
+ if ((*std) & V4L2_STD_PAL) {
ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
&flags);
} else if ((*std) & V4L2_STD_NTSC) {
@@ -3211,185 +3103,144 @@ out:
return ret;
}
-static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs,
+static int vino_enum_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_fmtdesc *fd)
{
- enum v4l2_buf_type type = fd->type;
- int index = fd->index;
- dprintk("format index = %d\n", index);
+ dprintk("format index = %d\n", fd->index);
- switch (fd->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if ((fd->index < 0) ||
- (fd->index >= VINO_DATA_FMT_COUNT))
- return -EINVAL;
- dprintk("format name = %s\n",
- vino_data_formats[index].description);
-
- memset(fd, 0, sizeof(struct v4l2_fmtdesc));
- fd->index = index;
- fd->type = type;
- fd->pixelformat = vino_data_formats[index].pixelformat;
- strcpy(fd->description, vino_data_formats[index].description);
- break;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
+ if (fd->index >= VINO_DATA_FMT_COUNT)
return -EINVAL;
- }
+ dprintk("format name = %s\n", vino_data_formats[fd->index].description);
+ fd->pixelformat = vino_data_formats[fd->index].pixelformat;
+ strcpy(fd->description, vino_data_formats[fd->index].description);
return 0;
}
-static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
+static int vino_try_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_format *f)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
struct vino_channel_settings tempvcs;
unsigned long flags;
+ struct v4l2_pix_format *pf = &f->fmt.pix;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- dprintk("requested: w = %d, h = %d\n",
- pf->width, pf->height);
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+ dprintk("requested: w = %d, h = %d\n",
+ pf->width, pf->height);
- tempvcs.data_format = vino_find_data_format(pf->pixelformat);
- if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
- tempvcs.data_format = VINO_DATA_FMT_GREY;
- pf->pixelformat =
- vino_data_formats[tempvcs.data_format].
- pixelformat;
- }
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+ memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- /* data format must be set before clipping/scaling */
- vino_set_scaling(&tempvcs, pf->width, pf->height);
+ tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+ if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+ tempvcs.data_format = VINO_DATA_FMT_GREY;
+ pf->pixelformat =
+ vino_data_formats[tempvcs.data_format].
+ pixelformat;
+ }
- dprintk("data format = %s\n",
- vino_data_formats[tempvcs.data_format].description);
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(&tempvcs, pf->width, pf->height);
- pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
- tempvcs.decimation;
- pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
- tempvcs.decimation;
+ dprintk("data format = %s\n",
+ vino_data_formats[tempvcs.data_format].description);
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = tempvcs.line_size;
- pf->sizeimage = tempvcs.line_size *
- (tempvcs.clipping.bottom - tempvcs.clipping.top) /
- tempvcs.decimation;
- pf->colorspace =
- vino_data_formats[tempvcs.data_format].colorspace;
+ pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+ tempvcs.decimation;
+ pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
- pf->priv = 0;
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = tempvcs.line_size;
+ pf->sizeimage = tempvcs.line_size *
+ (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
+ pf->colorspace =
+ vino_data_formats[tempvcs.data_format].colorspace;
+ pf->priv = 0;
return 0;
}
-static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
+static int vino_g_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_format *f)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
+ struct v4l2_pix_format *pf = &f->fmt.pix;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- pf->width = (vcs->clipping.right - vcs->clipping.left) /
- vcs->decimation;
- pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->pixelformat =
- vino_data_formats[vcs->data_format].pixelformat;
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = vcs->line_size;
- pf->sizeimage = vcs->line_size *
- (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->colorspace =
- vino_data_formats[vcs->data_format].colorspace;
+ pf->width = (vcs->clipping.right - vcs->clipping.left) /
+ vcs->decimation;
+ pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].pixelformat;
- pf->priv = 0;
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ pf->priv = 0;
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return 0;
}
-static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
+static int vino_s_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_format *f)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
int data_format;
unsigned long flags;
+ struct v4l2_pix_format *pf = &f->fmt.pix;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- data_format = vino_find_data_format(pf->pixelformat);
+ data_format = vino_find_data_format(pf->pixelformat);
- if (data_format == VINO_DATA_FMT_NONE) {
- vcs->data_format = VINO_DATA_FMT_GREY;
- pf->pixelformat =
- vino_data_formats[vcs->data_format].
- pixelformat;
- } else {
- vcs->data_format = data_format;
- }
+ if (data_format == VINO_DATA_FMT_NONE) {
+ vcs->data_format = VINO_DATA_FMT_GREY;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].
+ pixelformat;
+ } else {
+ vcs->data_format = data_format;
+ }
- /* data format must be set before clipping/scaling */
- vino_set_scaling(vcs, pf->width, pf->height);
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(vcs, pf->width, pf->height);
- dprintk("data format = %s\n",
- vino_data_formats[vcs->data_format].description);
+ dprintk("data format = %s\n",
+ vino_data_formats[vcs->data_format].description);
- pf->width = vcs->clipping.right - vcs->clipping.left;
- pf->height = vcs->clipping.bottom - vcs->clipping.top;
+ pf->width = vcs->clipping.right - vcs->clipping.left;
+ pf->height = vcs->clipping.bottom - vcs->clipping.top;
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = vcs->line_size;
- pf->sizeimage = vcs->line_size *
- (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->colorspace =
- vino_data_formats[vcs->data_format].colorspace;
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
- pf->priv = 0;
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ pf->priv = 0;
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return 0;
}
-static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
+static int vino_cropcap(struct file *file, void *__fh,
struct v4l2_cropcap *ccap)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
const struct vino_data_norm *norm;
unsigned long flags;
@@ -3419,9 +3270,10 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
+static int vino_g_crop(struct file *file, void *__fh,
struct v4l2_crop *c)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
switch (c->type) {
@@ -3443,9 +3295,10 @@ static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
+static int vino_s_crop(struct file *file, void *__fh,
struct v4l2_crop *c)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
switch (c->type) {
@@ -3465,108 +3318,83 @@ static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
+static int vino_g_parm(struct file *file, void *__fh,
struct v4l2_streamparm *sp)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
- switch (sp->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_captureparm *cp = &sp->parm.capture;
- memset(cp, 0, sizeof(struct v4l2_captureparm));
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = 1;
- cp->capability = V4L2_CAP_TIMEPERFRAME;
- cp->timeperframe.numerator = 1;
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+ cp->timeperframe.denominator = vcs->fps;
- cp->timeperframe.denominator = vcs->fps;
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- // TODO: cp->readbuffers = xxx;
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ /* TODO: cp->readbuffers = xxx; */
return 0;
}
-static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
+static int vino_s_parm(struct file *file, void *__fh,
struct v4l2_streamparm *sp)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
- switch (sp->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_captureparm *cp = &sp->parm.capture;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- if ((cp->timeperframe.numerator == 0) ||
- (cp->timeperframe.denominator == 0)) {
- /* reset framerate */
- vino_set_default_framerate(vcs);
- } else {
- vino_set_framerate(vcs, cp->timeperframe.denominator /
- cp->timeperframe.numerator);
- }
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- // TODO: set buffers according to cp->readbuffers
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
+ if ((cp->timeperframe.numerator == 0) ||
+ (cp->timeperframe.denominator == 0)) {
+ /* reset framerate */
+ vino_set_default_framerate(vcs);
+ } else {
+ vino_set_framerate(vcs, cp->timeperframe.denominator /
+ cp->timeperframe.numerator);
}
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
return 0;
}
-static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
+static int vino_reqbufs(struct file *file, void *__fh,
struct v4l2_requestbuffers *rb)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
+
if (vcs->reading)
return -EBUSY;
- switch (rb->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- // TODO: check queue type
- if (rb->memory != V4L2_MEMORY_MMAP) {
- dprintk("type not mmap\n");
- return -EINVAL;
- }
+ /* TODO: check queue type */
+ if (rb->memory != V4L2_MEMORY_MMAP) {
+ dprintk("type not mmap\n");
+ return -EINVAL;
+ }
- dprintk("count = %d\n", rb->count);
- if (rb->count > 0) {
- if (vino_is_capturing(vcs)) {
- dprintk("busy, capturing\n");
- return -EBUSY;
- }
+ dprintk("count = %d\n", rb->count);
+ if (rb->count > 0) {
+ if (vino_is_capturing(vcs)) {
+ dprintk("busy, capturing\n");
+ return -EBUSY;
+ }
- if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
- dprintk("busy, buffers still mapped\n");
- return -EBUSY;
- } else {
- vcs->streaming = 0;
- vino_queue_free(&vcs->fb_queue);
- vino_queue_init(&vcs->fb_queue, &rb->count);
- }
+ if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
+ dprintk("busy, buffers still mapped\n");
+ return -EBUSY;
} else {
vcs->streaming = 0;
- vino_capture_stop(vcs);
vino_queue_free(&vcs->fb_queue);
+ vino_queue_init(&vcs->fb_queue, &rb->count);
}
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
+ } else {
+ vcs->streaming = 0;
+ vino_capture_stop(vcs);
+ vino_queue_free(&vcs->fb_queue);
}
return 0;
@@ -3610,156 +3438,135 @@ static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
fb->id, fb->size, fb->data_size, fb->offset);
}
-static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
+static int vino_querybuf(struct file *file, void *__fh,
struct v4l2_buffer *b)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
+ struct vino_framebuffer *fb;
+
if (vcs->reading)
return -EBUSY;
- switch (b->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct vino_framebuffer *fb;
-
- // TODO: check queue type
- if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
- dprintk("invalid index = %d\n",
- b->index);
- return -EINVAL;
- }
-
- fb = vino_queue_get_buffer(&vcs->fb_queue,
- b->index);
- if (fb == NULL) {
- dprintk("vino_queue_get_buffer() failed");
- return -EINVAL;
- }
-
- vino_v4l2_get_buffer_status(vcs, fb, b);
- break;
+ /* TODO: check queue type */
+ if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
+ dprintk("invalid index = %d\n",
+ b->index);
+ return -EINVAL;
}
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
+
+ fb = vino_queue_get_buffer(&vcs->fb_queue,
+ b->index);
+ if (fb == NULL) {
+ dprintk("vino_queue_get_buffer() failed");
return -EINVAL;
}
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+
return 0;
}
-static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
+static int vino_qbuf(struct file *file, void *__fh,
struct v4l2_buffer *b)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
+ struct vino_framebuffer *fb;
+ int ret;
+
if (vcs->reading)
return -EBUSY;
- switch (b->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct vino_framebuffer *fb;
- int ret;
-
- // TODO: check queue type
- if (b->memory != V4L2_MEMORY_MMAP) {
- dprintk("type not mmap\n");
- return -EINVAL;
- }
+ /* TODO: check queue type */
+ if (b->memory != V4L2_MEMORY_MMAP) {
+ dprintk("type not mmap\n");
+ return -EINVAL;
+ }
- fb = vino_capture_enqueue(vcs, b->index);
- if (fb == NULL)
- return -EINVAL;
+ fb = vino_capture_enqueue(vcs, b->index);
+ if (fb == NULL)
+ return -EINVAL;
- vino_v4l2_get_buffer_status(vcs, fb, b);
+ vino_v4l2_get_buffer_status(vcs, fb, b);
- if (vcs->streaming) {
- ret = vino_capture_next(vcs, 1);
- if (ret)
- return ret;
- }
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
+ if (vcs->streaming) {
+ ret = vino_capture_next(vcs, 1);
+ if (ret)
+ return ret;
}
return 0;
}
-static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
- struct v4l2_buffer *b,
- unsigned int nonblocking)
+static int vino_dqbuf(struct file *file, void *__fh,
+ struct v4l2_buffer *b)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned int nonblocking = file->f_flags & O_NONBLOCK;
+ struct vino_framebuffer *fb;
+ unsigned int incoming, outgoing;
+ int err;
+
if (vcs->reading)
return -EBUSY;
- switch (b->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct vino_framebuffer *fb;
- unsigned int incoming, outgoing;
- int err;
+ /* TODO: check queue type */
- // TODO: check queue type
+ err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+ if (err) {
+ dprintk("vino_queue_get_incoming() failed\n");
+ return -EINVAL;
+ }
+ err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
+ if (err) {
+ dprintk("vino_queue_get_outgoing() failed\n");
+ return -EINVAL;
+ }
- err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
- if (err) {
- dprintk("vino_queue_get_incoming() failed\n");
+ dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
+
+ if (outgoing == 0) {
+ if (incoming == 0) {
+ dprintk("no incoming or outgoing buffers\n");
return -EINVAL;
}
- err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
- if (err) {
- dprintk("vino_queue_get_outgoing() failed\n");
- return -EINVAL;
+ if (nonblocking) {
+ dprintk("non-blocking I/O was selected and "
+ "there are no buffers to dequeue\n");
+ return -EAGAIN;
}
- dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
-
- if (outgoing == 0) {
- if (incoming == 0) {
- dprintk("no incoming or outgoing buffers\n");
- return -EINVAL;
- }
- if (nonblocking) {
- dprintk("non-blocking I/O was selected and "
- "there are no buffers to dequeue\n");
- return -EAGAIN;
- }
-
+ err = vino_wait_for_frame(vcs);
+ if (err) {
err = vino_wait_for_frame(vcs);
if (err) {
- err = vino_wait_for_frame(vcs);
- if (err) {
- /* interrupted or
- * no frames captured because
- * of frame skipping */
- // vino_capture_failed(vcs);
- return -EIO;
- }
+ /* interrupted or no frames captured because of
+ * frame skipping */
+ /* vino_capture_failed(vcs); */
+ return -EIO;
}
}
+ }
- fb = vino_queue_remove(&vcs->fb_queue, &b->index);
- if (fb == NULL) {
- dprintk("vino_queue_remove() failed\n");
- return -EINVAL;
- }
-
- err = vino_check_buffer(vcs, fb);
+ fb = vino_queue_remove(&vcs->fb_queue, &b->index);
+ if (fb == NULL) {
+ dprintk("vino_queue_remove() failed\n");
+ return -EINVAL;
+ }
- vino_v4l2_get_buffer_status(vcs, fb, b);
+ err = vino_check_buffer(vcs, fb);
- if (err)
- return -EIO;
+ vino_v4l2_get_buffer_status(vcs, fb, b);
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ if (err)
+ return -EIO;
return 0;
}
-static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
+static int vino_streamon(struct file *file, void *__fh,
+ enum v4l2_buf_type i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned int incoming;
int ret;
if (vcs->reading)
@@ -3796,8 +3603,10 @@ static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
return 0;
}
-static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
+static int vino_streamoff(struct file *file, void *__fh,
+ enum v4l2_buf_type i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
if (vcs->reading)
return -EBUSY;
@@ -3810,9 +3619,10 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
return 0;
}
-static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
+static int vino_queryctrl(struct file *file, void *__fh,
struct v4l2_queryctrl *queryctrl)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int i;
int err = 0;
@@ -3859,9 +3669,10 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
return err;
}
-static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
+static int vino_g_ctrl(struct file *file, void *__fh,
struct v4l2_control *control)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int i;
int err = 0;
@@ -3870,56 +3681,38 @@ static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
switch (vcs->input) {
case VINO_INPUT_D1: {
- struct indycam_control indycam_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
- if (vino_indycam_v4l2_controls[i].id ==
- control->id) {
- goto found1;
+ if (vino_indycam_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
- err = -EINVAL;
- goto out;
-
-found1:
- indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
-
- err = i2c_camera_command(DECODER_INDYCAM_GET_CONTROL,
- &indycam_ctrl);
- if (err) {
- err = -EINVAL;
+ if (err)
goto out;
- }
- control->value = indycam_ctrl.value;
+ err = camera_call(core, g_ctrl, control);
+ if (err)
+ err = -EINVAL;
break;
}
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO: {
- struct saa7191_control saa7191_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
- if (vino_saa7191_v4l2_controls[i].id ==
- control->id) {
- goto found2;
+ if (vino_saa7191_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
- err = -EINVAL;
- goto out;
-
-found2:
- saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
-
- err = i2c_decoder_command(DECODER_SAA7191_GET_CONTROL,
- &saa7191_ctrl);
- if (err) {
- err = -EINVAL;
+ if (err)
goto out;
- }
- control->value = saa7191_ctrl.value;
+ err = decoder_call(core, g_ctrl, control);
+ if (err)
+ err = -EINVAL;
break;
}
default:
@@ -3932,9 +3725,10 @@ out:
return err;
}
-static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
+static int vino_s_ctrl(struct file *file, void *__fh,
struct v4l2_control *control)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int i;
int err = 0;
@@ -3948,65 +3742,43 @@ static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
switch (vcs->input) {
case VINO_INPUT_D1: {
- struct indycam_control indycam_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
- if (vino_indycam_v4l2_controls[i].id ==
- control->id) {
- if ((control->value >=
- vino_indycam_v4l2_controls[i].minimum)
- && (control->value <=
- vino_indycam_v4l2_controls[i].
- maximum)) {
- goto found1;
- } else {
- err = -ERANGE;
- goto out;
- }
+ if (vino_indycam_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
-
- err = -EINVAL;
- goto out;
-
-found1:
- indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
- indycam_ctrl.value = control->value;
-
- err = i2c_camera_command(DECODER_INDYCAM_SET_CONTROL,
- &indycam_ctrl);
+ if (err)
+ goto out;
+ if (control->value < vino_indycam_v4l2_controls[i].minimum ||
+ control->value > vino_indycam_v4l2_controls[i].maximum) {
+ err = -ERANGE;
+ goto out;
+ }
+ err = camera_call(core, s_ctrl, control);
if (err)
err = -EINVAL;
break;
}
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO: {
- struct saa7191_control saa7191_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
- if (vino_saa7191_v4l2_controls[i].id ==
- control->id) {
- if ((control->value >=
- vino_saa7191_v4l2_controls[i].minimum)
- && (control->value <=
- vino_saa7191_v4l2_controls[i].
- maximum)) {
- goto found2;
- } else {
- err = -ERANGE;
- goto out;
- }
+ if (vino_saa7191_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
- err = -EINVAL;
- goto out;
-
-found2:
- saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
- saa7191_ctrl.value = control->value;
+ if (err)
+ goto out;
+ if (control->value < vino_saa7191_v4l2_controls[i].minimum ||
+ control->value > vino_saa7191_v4l2_controls[i].maximum) {
+ err = -ERANGE;
+ goto out;
+ }
- err = i2c_decoder_command(DECODER_SAA7191_SET_CONTROL,
- &saa7191_ctrl);
+ err = decoder_call(core, s_ctrl, control);
if (err)
err = -EINVAL;
break;
@@ -4237,116 +4009,9 @@ over:
ret = POLLIN | POLLRDNORM;
error:
-
return ret;
}
-static long vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
-
-#ifdef VINO_DEBUG
- switch (_IOC_TYPE(cmd)) {
- case 'v':
- dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
- break;
- case 'V':
- dprintk("ioctl(): V4L2 %s (0x%08x)\n",
- v4l2_ioctl_names[_IOC_NR(cmd)], cmd);
- break;
- default:
- dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
- }
-#endif
-
- switch (cmd) {
- /* V4L2 interface */
- case VIDIOC_QUERYCAP: {
- vino_v4l2_querycap(arg);
- break;
- }
- case VIDIOC_ENUMINPUT: {
- return vino_v4l2_enuminput(vcs, arg);
- }
- case VIDIOC_G_INPUT: {
- return vino_v4l2_g_input(vcs, arg);
- }
- case VIDIOC_S_INPUT: {
- return vino_v4l2_s_input(vcs, arg);
- }
- case VIDIOC_ENUMSTD: {
- return vino_v4l2_enumstd(vcs, arg);
- }
- case VIDIOC_QUERYSTD: {
- return vino_v4l2_querystd(vcs, arg);
- }
- case VIDIOC_G_STD: {
- return vino_v4l2_g_std(vcs, arg);
- }
- case VIDIOC_S_STD: {
- return vino_v4l2_s_std(vcs, arg);
- }
- case VIDIOC_ENUM_FMT: {
- return vino_v4l2_enum_fmt(vcs, arg);
- }
- case VIDIOC_TRY_FMT: {
- return vino_v4l2_try_fmt(vcs, arg);
- }
- case VIDIOC_G_FMT: {
- return vino_v4l2_g_fmt(vcs, arg);
- }
- case VIDIOC_S_FMT: {
- return vino_v4l2_s_fmt(vcs, arg);
- }
- case VIDIOC_CROPCAP: {
- return vino_v4l2_cropcap(vcs, arg);
- }
- case VIDIOC_G_CROP: {
- return vino_v4l2_g_crop(vcs, arg);
- }
- case VIDIOC_S_CROP: {
- return vino_v4l2_s_crop(vcs, arg);
- }
- case VIDIOC_G_PARM: {
- return vino_v4l2_g_parm(vcs, arg);
- }
- case VIDIOC_S_PARM: {
- return vino_v4l2_s_parm(vcs, arg);
- }
- case VIDIOC_REQBUFS: {
- return vino_v4l2_reqbufs(vcs, arg);
- }
- case VIDIOC_QUERYBUF: {
- return vino_v4l2_querybuf(vcs, arg);
- }
- case VIDIOC_QBUF: {
- return vino_v4l2_qbuf(vcs, arg);
- }
- case VIDIOC_DQBUF: {
- return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK);
- }
- case VIDIOC_STREAMON: {
- return vino_v4l2_streamon(vcs);
- }
- case VIDIOC_STREAMOFF: {
- return vino_v4l2_streamoff(vcs);
- }
- case VIDIOC_QUERYCTRL: {
- return vino_v4l2_queryctrl(vcs, arg);
- }
- case VIDIOC_G_CTRL: {
- return vino_v4l2_g_ctrl(vcs, arg);
- }
- case VIDIOC_S_CTRL: {
- return vino_v4l2_s_ctrl(vcs, arg);
- }
- default:
- return -ENOIOCTLCMD;
- }
-
- return 0;
-}
-
static long vino_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -4356,7 +4021,7 @@ static long vino_ioctl(struct file *file,
if (mutex_lock_interruptible(&vcs->mutex))
return -EINTR;
- ret = video_usercopy(file, cmd, arg, vino_do_ioctl);
+ ret = video_ioctl2(file, cmd, arg);
mutex_unlock(&vcs->mutex);
@@ -4368,45 +4033,75 @@ static long vino_ioctl(struct file *file,
/* __initdata */
static int vino_init_stage;
+const struct v4l2_ioctl_ops vino_ioctl_ops = {
+ .vidioc_enum_fmt_vid_cap = vino_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vino_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vino_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vino_try_fmt_vid_cap,
+ .vidioc_querycap = vino_querycap,
+ .vidioc_enum_input = vino_enum_input,
+ .vidioc_g_input = vino_g_input,
+ .vidioc_s_input = vino_s_input,
+ .vidioc_g_std = vino_g_std,
+ .vidioc_s_std = vino_s_std,
+ .vidioc_querystd = vino_querystd,
+ .vidioc_cropcap = vino_cropcap,
+ .vidioc_s_crop = vino_s_crop,
+ .vidioc_g_crop = vino_g_crop,
+ .vidioc_s_parm = vino_s_parm,
+ .vidioc_g_parm = vino_g_parm,
+ .vidioc_reqbufs = vino_reqbufs,
+ .vidioc_querybuf = vino_querybuf,
+ .vidioc_qbuf = vino_qbuf,
+ .vidioc_dqbuf = vino_dqbuf,
+ .vidioc_streamon = vino_streamon,
+ .vidioc_streamoff = vino_streamoff,
+ .vidioc_queryctrl = vino_queryctrl,
+ .vidioc_g_ctrl = vino_g_ctrl,
+ .vidioc_s_ctrl = vino_s_ctrl,
+};
+
static const struct v4l2_file_operations vino_fops = {
.owner = THIS_MODULE,
.open = vino_open,
.release = vino_close,
- .ioctl = vino_ioctl,
+ .unlocked_ioctl = vino_ioctl,
.mmap = vino_mmap,
.poll = vino_poll,
};
-static struct video_device v4l_device_template = {
+static struct video_device vdev_template = {
.name = "NOT SET",
.fops = &vino_fops,
+ .ioctl_ops = &vino_ioctl_ops,
+ .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
.minor = -1,
};
static void vino_module_cleanup(int stage)
{
switch(stage) {
+ case 11:
+ video_unregister_device(vino_drvdata->b.vdev);
+ vino_drvdata->b.vdev = NULL;
case 10:
- video_unregister_device(vino_drvdata->b.v4l_device);
- vino_drvdata->b.v4l_device = NULL;
+ video_unregister_device(vino_drvdata->a.vdev);
+ vino_drvdata->a.vdev = NULL;
case 9:
- video_unregister_device(vino_drvdata->a.v4l_device);
- vino_drvdata->a.v4l_device = NULL;
+ i2c_del_adapter(&vino_i2c_adapter);
case 8:
- vino_i2c_del_bus();
- case 7:
free_irq(SGI_VINO_IRQ, NULL);
+ case 7:
+ if (vino_drvdata->b.vdev) {
+ video_device_release(vino_drvdata->b.vdev);
+ vino_drvdata->b.vdev = NULL;
+ }
case 6:
- if (vino_drvdata->b.v4l_device) {
- video_device_release(vino_drvdata->b.v4l_device);
- vino_drvdata->b.v4l_device = NULL;
+ if (vino_drvdata->a.vdev) {
+ video_device_release(vino_drvdata->a.vdev);
+ vino_drvdata->a.vdev = NULL;
}
case 5:
- if (vino_drvdata->a.v4l_device) {
- video_device_release(vino_drvdata->a.v4l_device);
- vino_drvdata->a.v4l_device = NULL;
- }
- case 4:
/* all entries in dma_cpu dummy table have the same address */
dma_unmap_single(NULL,
vino_drvdata->dummy_desc_table.dma_cpu[0],
@@ -4416,8 +4111,10 @@ static void vino_module_cleanup(int stage)
(void *)vino_drvdata->
dummy_desc_table.dma_cpu,
vino_drvdata->dummy_desc_table.dma);
- case 3:
+ case 4:
free_page(vino_drvdata->dummy_page);
+ case 3:
+ v4l2_device_unregister(&vino_drvdata->v4l2_dev);
case 2:
kfree(vino_drvdata);
case 1:
@@ -4472,6 +4169,7 @@ static int vino_probe(void)
static int vino_init(void)
{
dma_addr_t dma_dummy_address;
+ int err;
int i;
vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL);
@@ -4480,6 +4178,12 @@ static int vino_init(void)
return -ENOMEM;
}
vino_init_stage++;
+ strlcpy(vino_drvdata->v4l2_dev.name, "vino",
+ sizeof(vino_drvdata->v4l2_dev.name));
+ err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev);
+ if (err)
+ return err;
+ vino_init_stage++;
/* create a dummy dma descriptor */
vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
@@ -4546,25 +4250,27 @@ static int vino_init_channel_settings(struct vino_channel_settings *vcs,
spin_lock_init(&vcs->fb_queue.queue_lock);
init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
- vcs->v4l_device = video_device_alloc();
- if (!vcs->v4l_device) {
+ vcs->vdev = video_device_alloc();
+ if (!vcs->vdev) {
vino_module_cleanup(vino_init_stage);
return -ENOMEM;
}
vino_init_stage++;
- memcpy(vcs->v4l_device, &v4l_device_template,
+ memcpy(vcs->vdev, &vdev_template,
sizeof(struct video_device));
- strcpy(vcs->v4l_device->name, name);
- vcs->v4l_device->release = video_device_release;
+ strcpy(vcs->vdev->name, name);
+ vcs->vdev->release = video_device_release;
+ vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev;
- video_set_drvdata(vcs->v4l_device, vcs);
+ video_set_drvdata(vcs->vdev, vcs);
return 0;
}
static int __init vino_module_init(void)
{
+ unsigned short addr[] = { 0, I2C_CLIENT_END };
int ret;
printk(KERN_INFO "SGI VINO driver version %s\n",
@@ -4584,12 +4290,12 @@ static int __init vino_module_init(void)
spin_lock_init(&vino_drvdata->input_lock);
ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
- vino_v4l_device_name_a);
+ vino_vdev_name_a);
if (ret)
return ret;
ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
- vino_v4l_device_name_b);
+ vino_vdev_name_b);
if (ret)
return ret;
@@ -4605,15 +4311,16 @@ static int __init vino_module_init(void)
}
vino_init_stage++;
- ret = vino_i2c_add_bus();
+ ret = i2c_add_adapter(&vino_i2c_adapter);
if (ret) {
printk(KERN_ERR "VINO I2C bus registration failed\n");
vino_module_cleanup(vino_init_stage);
return ret;
}
+ i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev);
vino_init_stage++;
- ret = video_register_device(vino_drvdata->a.v4l_device,
+ ret = video_register_device(vino_drvdata->a.vdev,
VFL_TYPE_GRABBER, -1);
if (ret < 0) {
printk(KERN_ERR "VINO channel A Video4Linux-device "
@@ -4623,7 +4330,7 @@ static int __init vino_module_init(void)
}
vino_init_stage++;
- ret = video_register_device(vino_drvdata->b.v4l_device,
+ ret = video_register_device(vino_drvdata->b.vdev,
VFL_TYPE_GRABBER, -1);
if (ret < 0) {
printk(KERN_ERR "VINO channel B Video4Linux-device "
@@ -4633,10 +4340,12 @@ static int __init vino_module_init(void)
}
vino_init_stage++;
-#ifdef MODULE
- request_module("saa7191");
- request_module("indycam");
-#endif
+ addr[0] = 0x45;
+ vino_drvdata->decoder = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
+ "saa7191", "saa7191", addr);
+ addr[0] = 0x2b;
+ vino_drvdata->camera = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
+ "indycam", "indycam", addr);
dprintk("init complete!\n");
diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c
index 76f7dfc32..e3bc2b0a3 100644
--- a/linux/drivers/media/video/vivi.c
+++ b/linux/drivers/media/video/vivi.c
@@ -29,10 +29,6 @@
#include "compat.h"
#include <linux/videodev2.h>
#include <linux/dma-mapping.h>
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/highmem.h>
@@ -1413,7 +1409,7 @@ free_dev:
*/
static int __init vivi_init(void)
{
- int ret, i;
+ int ret = 0, i;
if (n_devs <= 0)
n_devs = 1;
diff --git a/linux/drivers/media/video/vpx3220.c b/linux/drivers/media/video/vpx3220.c
index 0c1c97f2f..ee6c74176 100644
--- a/linux/drivers/media/video/vpx3220.c
+++ b/linux/drivers/media/video/vpx3220.c
@@ -374,7 +374,7 @@ static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
choosen video norm */
temp_input = vpx3220_fp_read(sd, 0xf2);
- v4l2_dbg(1, debug, sd, "VIDIOC_S_STD %llx\n", std);
+ v4l2_dbg(1, debug, sd, "VIDIOC_S_STD %llx\n", (unsigned long long)std);
if (std & V4L2_STD_NTSC) {
vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
diff --git a/linux/drivers/media/video/w9966.c b/linux/drivers/media/video/w9966.c
index b8ede9e3f..75d8debe7 100644
--- a/linux/drivers/media/video/w9966.c
+++ b/linux/drivers/media/video/w9966.c
@@ -58,7 +58,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include "compat.h"
-#include <linux/videodev2.h>
+#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <linux/parport.h>
diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c
index 0b5109ed9..cf8548a7f 100644
--- a/linux/drivers/media/video/w9968cf.c
+++ b/linux/drivers/media/video/w9968cf.c
@@ -42,6 +42,7 @@
#include <asm/page.h>
#include <asm/uaccess.h>
#include <linux/page-flags.h>
+#include <linux/videodev.h>
#include <media/v4l2-ioctl.h>
#include "w9968cf.h"
@@ -68,7 +69,6 @@ MODULE_VERSION(W9968CF_MODULE_VERSION);
MODULE_LICENSE(W9968CF_MODULE_LICENSE);
MODULE_SUPPORTED_DEVICE("Video");
-static int ovmod_load = W9968CF_OVMOD_LOAD;
static unsigned short simcams = W9968CF_SIMCAMS;
static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
@@ -111,9 +111,6 @@ static int specific_debug = W9968CF_SPECIFIC_DEBUG;
static unsigned int param_nv[24]; /* number of values per parameter */
-#ifdef CONFIG_MODULES
-module_param(ovmod_load, bool, 0644);
-#endif
module_param(simcams, ushort, 0644);
module_param_array(video_nr, short, &param_nv[0], 0444);
module_param_array(packet_size, uint, &param_nv[1], 0444);
@@ -144,18 +141,6 @@ module_param(debug, ushort, 0644);
module_param(specific_debug, bool, 0644);
#endif
-#ifdef CONFIG_MODULES
-MODULE_PARM_DESC(ovmod_load,
- "\n<0|1> Automatic 'ovcamchip' module loading."
- "\n0 disabled, 1 enabled."
- "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
- "\nmodule in the system, according to its configuration, and"
- "\nattempts to load that module automatically. This action is"
- "\nperformed once as soon as the 'w9968cf' module is loaded"
- "\ninto memory."
- "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
- "\n");
-#endif
MODULE_PARM_DESC(simcams,
"\n<n> Number of cameras allowed to stream simultaneously."
"\nn may vary from 0 to "
@@ -447,8 +432,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data*);
static u32 w9968cf_i2c_func(struct i2c_adapter*);
-static int w9968cf_i2c_attach_inform(struct i2c_client*);
-static int w9968cf_i2c_detach_inform(struct i2c_client*);
/* Memory management */
static void* rvmalloc(unsigned long size);
@@ -1451,19 +1434,11 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data)
{
- struct w9968cf_device* cam = i2c_get_adapdata(adapter);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+ struct w9968cf_device *cam = to_cam(v4l2_dev);
u8 i;
int err = 0;
- switch (addr) {
- case OV6xx0_SID:
- case OV7xx0_SID:
- break;
- default:
- DBG(4, "Rejected slave ID 0x%04X", addr)
- return -EINVAL;
- }
-
if (size == I2C_SMBUS_BYTE) {
/* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
addr <<= 1;
@@ -1471,8 +1446,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
if (read_write == I2C_SMBUS_WRITE)
err = w9968cf_i2c_adap_write_byte(cam, addr, command);
else if (read_write == I2C_SMBUS_READ)
- err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
-
+ for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+ err = w9968cf_i2c_adap_read_byte(cam, addr,
+ &data->byte);
+ if (err) {
+ if (w9968cf_smbus_refresh_bus(cam)) {
+ err = -EIO;
+ break;
+ }
+ } else
+ break;
+ }
} else if (size == I2C_SMBUS_BYTE_DATA) {
addr <<= 1;
@@ -1499,7 +1483,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
DBG(4, "Unsupported I2C transfer mode (%d)", size)
return -EINVAL;
}
-
return err;
}
@@ -1512,44 +1495,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
}
-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
-{
- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
- int id = client->driver->id, err = 0;
-
- if (id == I2C_DRIVERID_OVCAMCHIP) {
- cam->sensor_client = client;
- err = w9968cf_sensor_init(cam);
- if (err) {
- cam->sensor_client = NULL;
- return err;
- }
- } else {
- DBG(4, "Rejected client [%s] with driver [%s]",
- client->name, client->driver->driver.name)
- return -EINVAL;
- }
-
- DBG(5, "I2C attach client [%s] with driver [%s]",
- client->name, client->driver->driver.name)
-
- return 0;
-}
-
-
-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
-{
- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-
- if (cam->sensor_client == client)
- cam->sensor_client = NULL;
-
- DBG(5, "I2C detach client [%s]", client->name)
-
- return 0;
-}
-
-
static int w9968cf_i2c_init(struct w9968cf_device* cam)
{
int err = 0;
@@ -1565,15 +1510,16 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
static struct i2c_adapter adap = {
.id = I2C_HW_SMBUS_W9968CF,
.owner = THIS_MODULE,
- .client_register = w9968cf_i2c_attach_inform,
- .client_unregister = w9968cf_i2c_detach_inform,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+ .class = I2C_CLASS_TV_ANALOG,
+#endif
.algo = &algo,
};
memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
strcpy(cam->i2c_adapter.name, "w9968cf");
cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
- i2c_set_adapdata(&cam->i2c_adapter, cam);
+ i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
DBG(6, "Registering I2C adapter with kernel...")
@@ -2176,13 +2122,9 @@ w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
static int
w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
{
- struct i2c_client* c = cam->sensor_client;
- int rc = 0;
+ int rc;
- if (!c || !c->driver || !c->driver->command)
- return -EINVAL;
-
- rc = c->driver->command(c, cmd, arg);
+ rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
/* The I2C driver returns -EPERM on non-supported controls */
return (rc < 0 && rc != -EPERM) ? rc : 0;
}
@@ -2357,7 +2299,7 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam)
goto error;
/* NOTE: Make sure width and height are a multiple of 16 */
- switch (cam->sensor_client->addr) {
+ switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
case OV6xx0_SID:
cam->maxwidth = 352;
cam->maxheight = 288;
@@ -2662,6 +2604,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
w9968cf_deallocate_memory(cam);
kfree(cam->control_buffer);
kfree(cam->data_buffer);
+ v4l2_device_unregister(&cam->v4l2_dev);
mutex_unlock(&w9968cf_devlist_mutex);
}
@@ -3491,6 +3434,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
struct list_head* ptr;
u8 sc = 0; /* number of simultaneous cameras */
static unsigned short dev_nr; /* 0 - we are handling device number n */
+ static unsigned short addrs[] = {
+ OV7xx0_SID,
+ OV6xx0_SID,
+ I2C_CLIENT_END
+ };
if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor &&
le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
@@ -3506,12 +3454,14 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
if (!cam)
return -ENOMEM;
+ err = v4l2_device_register(&udev->dev, &cam->v4l2_dev);
+ if (err)
+ goto fail0;
+
mutex_init(&cam->dev_mutex);
mutex_lock(&cam->dev_mutex);
cam->usbdev = udev;
- /* NOTE: a local copy is used to avoid possible race conditions */
- memcpy(&cam->dev, &udev->dev, sizeof(struct device));
DBG(2, "%s detected", symbolic(camlist, mod_id))
@@ -3560,7 +3510,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- cam->v4ldev->parent = &cam->dev;
+ cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -3587,9 +3537,13 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
w9968cf_turn_on_led(cam);
w9968cf_i2c_init(cam);
+ cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter,
+ "ovcamchip", "ovcamchip", addrs);
usb_set_intfdata(intf, cam);
mutex_unlock(&cam->dev_mutex);
+
+ err = w9968cf_sensor_init(cam);
return 0;
fail: /* Free unused memory */
@@ -3598,6 +3552,8 @@ fail: /* Free unused memory */
if (cam->v4ldev)
video_device_release(cam->v4ldev);
mutex_unlock(&cam->dev_mutex);
+ v4l2_device_unregister(&cam->v4l2_dev);
+fail0:
kfree(cam);
return err;
}
@@ -3608,15 +3564,16 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
struct w9968cf_device* cam =
(struct w9968cf_device*)usb_get_intfdata(intf);
- down_write(&w9968cf_disconnect);
-
if (cam) {
+ down_write(&w9968cf_disconnect);
/* Prevent concurrent accesses to data */
mutex_lock(&cam->dev_mutex);
cam->disconnected = 1;
- DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
+ DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
+
+ v4l2_device_disconnect(&cam->v4l2_dev);
wake_up_interruptible_all(&cam->open);
@@ -3632,12 +3589,12 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
w9968cf_release_resources(cam);
mutex_unlock(&cam->dev_mutex);
+ up_write(&w9968cf_disconnect);
- if (!cam->users)
+ if (!cam->users) {
kfree(cam);
+ }
}
-
- up_write(&w9968cf_disconnect);
}
@@ -3661,9 +3618,6 @@ static int __init w9968cf_module_init(void)
KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
KDBG(3, W9968CF_MODULE_AUTHOR)
- if (ovmod_load)
- request_module("ovcamchip");
-
if ((err = usb_register(&w9968cf_usb_driver)))
return err;
diff --git a/linux/drivers/media/video/w9968cf.h b/linux/drivers/media/video/w9968cf.h
index 62c26b1ed..989d414d6 100644
--- a/linux/drivers/media/video/w9968cf.h
+++ b/linux/drivers/media/video/w9968cf.h
@@ -33,6 +33,7 @@
#include <linux/rwsem.h>
#include <linux/mutex.h>
+#include <media/v4l2-device.h>
#include <media/ovcamchip.h>
#include "compat.h"
@@ -43,7 +44,6 @@
* Default values *
****************************************************************************/
-#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */
#define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */
/* Comment/uncomment the following line to enable/disable debugging messages */
@@ -196,10 +196,9 @@ enum w9968cf_vpp_flag {
/* Main device driver structure */
struct w9968cf_device {
- struct device dev; /* device structure */
-
enum w9968cf_model_id id; /* private device identifier */
+ struct v4l2_device v4l2_dev;
struct video_device* v4ldev; /* -> V4L structure */
struct list_head v4llist; /* entry of the list of V4L cameras */
@@ -266,7 +265,7 @@ struct w9968cf_device {
/* I2C interface to kernel */
struct i2c_adapter i2c_adapter;
- struct i2c_client* sensor_client;
+ struct v4l2_subdev *sensor_sd;
/* Locks */
struct mutex dev_mutex, /* for probe, disconnect,open and close */
@@ -278,6 +277,11 @@ struct w9968cf_device {
char command[16]; /* name of the program holding the device */
};
+static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
+}
+
/****************************************************************************
* Macros for debugging *
@@ -292,14 +296,14 @@ struct w9968cf_device {
if ( ((specific_debug) && (debug == (level))) || \
((!specific_debug) && (debug >= (level))) ) { \
if ((level) == 1) \
- dev_err(&cam->dev, fmt "\n", ## args); \
+ v4l2_err(&cam->v4l2_dev, fmt "\n", ## args); \
else if ((level) == 2 || (level) == 3) \
- dev_info(&cam->dev, fmt "\n", ## args); \
+ v4l2_info(&cam->v4l2_dev, fmt "\n", ## args); \
else if ((level) == 4) \
- dev_warn(&cam->dev, fmt "\n", ## args); \
+ v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args); \
else if ((level) >= 5) \
- dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args); \
+ v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", \
+ __func__, __LINE__ , ## args); \
} \
}
/* For generic kernel (not device specific) messages */
@@ -322,7 +326,7 @@ struct w9968cf_device {
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
+v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
diff --git a/linux/drivers/media/video/zoran/Kconfig b/linux/drivers/media/video/zoran/Kconfig
index 925fb5159..fd4120e4c 100644
--- a/linux/drivers/media/video/zoran/Kconfig
+++ b/linux/drivers/media/video/zoran/Kconfig
@@ -68,6 +68,7 @@ config VIDEO_ZORAN_AVS6EYES
tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL
select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
help
Support for the AverMedia 6 Eyes video surveillance card.
diff --git a/linux/drivers/media/video/zoran/zoran.h b/linux/drivers/media/video/zoran/zoran.h
index 8beada961..afecf32f1 100644
--- a/linux/drivers/media/video/zoran/zoran.h
+++ b/linux/drivers/media/video/zoran/zoran.h
@@ -172,6 +172,8 @@ Private IOCTL to set up for displaying MJPEG
#endif
#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1)
+#define MAX_FRAME (BUZ_MAX_FRAME > VIDEO_MAX_FRAME ? BUZ_MAX_FRAME : VIDEO_MAX_FRAME)
+
#include "zr36057.h"
enum card_type {
@@ -280,21 +282,21 @@ struct zoran_mapping {
int count;
};
-struct zoran_jpg_buffer {
- struct zoran_mapping *map;
- __le32 *frag_tab; /* addresses of frag table */
- u32 frag_tab_bus; /* same value cached to save time in ISR */
- enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */
- struct zoran_sync bs; /* DONE: info to return to application */
-};
-
-struct zoran_v4l_buffer {
+struct zoran_buffer {
struct zoran_mapping *map;
- char *fbuffer; /* virtual address of frame buffer */
- unsigned long fbuffer_phys; /* physical address of frame buffer */
- unsigned long fbuffer_bus; /* bus address of frame buffer */
- enum zoran_buffer_state state; /* state: unused/pending/done */
- struct zoran_sync bs; /* DONE: info to return to application */
+ enum zoran_buffer_state state; /* state: unused/pending/dma/done */
+ struct zoran_sync bs; /* DONE: info to return to application */
+ union {
+ struct {
+ __le32 *frag_tab; /* addresses of frag table */
+ u32 frag_tab_bus; /* same value cached to save time in ISR */
+ } jpg;
+ struct {
+ char *fbuffer; /* virtual address of frame buffer */
+ unsigned long fbuffer_phys;/* physical address of frame buffer */
+ unsigned long fbuffer_bus;/* bus address of frame buffer */
+ } v4l;
+ };
};
enum zoran_lock_activity {
@@ -304,19 +306,13 @@ enum zoran_lock_activity {
};
/* buffer collections */
-struct zoran_jpg_struct {
+struct zoran_buffer_col {
enum zoran_lock_activity active; /* feature currently in use? */
- struct zoran_jpg_buffer buffer[BUZ_MAX_FRAME]; /* buffers */
- int num_buffers, buffer_size;
+ unsigned int num_buffers, buffer_size;
+ struct zoran_buffer buffer[MAX_FRAME]; /* buffers */
u8 allocated; /* Flag if buffers are allocated */
u8 need_contiguous; /* Flag if contiguous buffers are needed */
-};
-
-struct zoran_v4l_struct {
- enum zoran_lock_activity active; /* feature currently in use? */
- struct zoran_v4l_buffer buffer[VIDEO_MAX_FRAME]; /* buffers */
- int num_buffers, buffer_size;
- u8 allocated; /* Flag if buffers are allocated */
+ /* only applies to jpg buffers, raw buffers are always contiguous */
};
struct zoran;
@@ -325,17 +321,16 @@ struct zoran;
struct zoran_fh {
struct zoran *zr;
- enum zoran_map_mode map_mode; /* Flag which bufferset will map by next mmap() */
+ enum zoran_map_mode map_mode; /* Flag which bufferset will map by next mmap() */
struct zoran_overlay_settings overlay_settings;
- u32 *overlay_mask; /* overlay mask */
- enum zoran_lock_activity overlay_active; /* feature currently in use? */
+ u32 *overlay_mask; /* overlay mask */
+ enum zoran_lock_activity overlay_active;/* feature currently in use? */
- struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */
- struct zoran_v4l_struct v4l_buffers; /* V4L buffers' info */
+ struct zoran_buffer_col buffers; /* buffers' info */
+ struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */
struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */
- struct zoran_jpg_struct jpg_buffers; /* MJPEG buffers' info */
};
struct card_info {
@@ -434,7 +429,7 @@ struct zoran {
unsigned long v4l_pend_tail;
unsigned long v4l_sync_tail;
int v4l_pend[V4L_MAX_FRAME];
- struct zoran_v4l_struct v4l_buffers; /* V4L buffers' info */
+ struct zoran_buffer_col v4l_buffers; /* V4L buffers' info */
/* Buz MJPEG parameters */
enum zoran_codec_mode codec_mode; /* status of codec */
@@ -461,7 +456,7 @@ struct zoran {
int jpg_pend[BUZ_MAX_FRAME];
/* array indexed by frame number */
- struct zoran_jpg_struct jpg_buffers; /* MJPEG buffers' info */
+ struct zoran_buffer_col jpg_buffers; /* MJPEG buffers' info */
/* Additional stuff for testing */
#ifdef CONFIG_PROC_FS
diff --git a/linux/drivers/media/video/zoran/zoran_card.c b/linux/drivers/media/video/zoran/zoran_card.c
index 57cc62d82..b7dea2b8a 100644
--- a/linux/drivers/media/video/zoran/zoran_card.c
+++ b/linux/drivers/media/video/zoran/zoran_card.c
@@ -38,9 +38,7 @@
#include <linux/proc_fs.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
-#include "compat.h"
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
#include <linux/spinlock.h>
#include <linux/sem.h>
#include <linux/kmod.h>
@@ -49,8 +47,10 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
+#include <media/v4l2-common.h>
+#include <media/bt819.h>
+#include "compat.h"
#include "videocodec.h"
#include "zoran.h"
@@ -255,7 +255,7 @@ zr36016_write (struct videocodec *codec,
static void
dc10_init (struct zoran *zr)
{
- dprintk(3, KERN_DEBUG "%s: dc10_init()\n", ZR_DEVNAME(zr));
+ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
/* Pixel clock selection */
GPIO(zr, 4, 0);
@@ -267,13 +267,13 @@ dc10_init (struct zoran *zr)
static void
dc10plus_init (struct zoran *zr)
{
- dprintk(3, KERN_DEBUG "%s: dc10plus_init()\n", ZR_DEVNAME(zr));
+ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
}
static void
buz_init (struct zoran *zr)
{
- dprintk(3, KERN_DEBUG "%s: buz_init()\n", ZR_DEVNAME(zr));
+ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
/* some stuff from Iomega */
pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
@@ -284,7 +284,7 @@ buz_init (struct zoran *zr)
static void
lml33_init (struct zoran *zr)
{
- dprintk(3, KERN_DEBUG "%s: lml33_init()\n", ZR_DEVNAME(zr));
+ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
GPIO(zr, 2, 1); // Set Composite input/output
}
@@ -759,13 +759,13 @@ zoran_check_jpg_settings (struct zoran *zr,
dprintk(4,
KERN_DEBUG
- "%s: check_jpg_settings() - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
- ZR_DEVNAME(zr), settings->decimation, settings->HorDcm,
+ "%s: %s - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
+ ZR_DEVNAME(zr), __func__, settings->decimation, settings->HorDcm,
settings->VerDcm, settings->TmpDcm);
dprintk(4,
KERN_DEBUG
- "%s: check_jpg_settings() - x: %d, y: %d, w: %d, y: %d\n",
- ZR_DEVNAME(zr), settings->img_x, settings->img_y,
+ "%s: %s - x: %d, y: %d, w: %d, y: %d\n",
+ ZR_DEVNAME(zr), __func__, settings->img_x, settings->img_y,
settings->img_width, settings->img_height);
/* Check decimation, set default values for decimation = 1, 2, 4 */
switch (settings->decimation) {
@@ -797,8 +797,8 @@ zoran_check_jpg_settings (struct zoran *zr,
if (zr->card.type == DC10_new) {
dprintk(1,
KERN_DEBUG
- "%s: check_jpg_settings() - HDec by 4 is not supported on the DC10\n",
- ZR_DEVNAME(zr));
+ "%s: %s - HDec by 4 is not supported on the DC10\n",
+ ZR_DEVNAME(zr), __func__);
err0++;
break;
}
@@ -875,16 +875,16 @@ zoran_check_jpg_settings (struct zoran *zr,
if (!try && err0) {
dprintk(1,
KERN_ERR
- "%s: check_jpg_settings() - error in params for decimation = 0\n",
- ZR_DEVNAME(zr));
+ "%s: %s - error in params for decimation = 0\n",
+ ZR_DEVNAME(zr), __func__);
err++;
}
break;
default:
dprintk(1,
KERN_ERR
- "%s: check_jpg_settings() - decimation = %d, must be 0, 1, 2 or 4\n",
- ZR_DEVNAME(zr), settings->decimation);
+ "%s: %s - decimation = %d, must be 0, 1, 2 or 4\n",
+ ZR_DEVNAME(zr), __func__, settings->decimation);
err++;
break;
}
@@ -964,10 +964,8 @@ zoran_open_init_params (struct zoran *zr)
JPEG_MARKER_DHT | JPEG_MARKER_DQT;
i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0);
if (i)
- dprintk(1,
- KERN_ERR
- "%s: zoran_open_init_params() internal error\n",
- ZR_DEVNAME(zr));
+ dprintk(1, KERN_ERR "%s: %s internal error\n",
+ ZR_DEVNAME(zr), __func__);
clear_interrupt_counters(zr);
zr->testing = 0;
@@ -1006,8 +1004,8 @@ zr36057_init (struct zoran *zr)
dprintk(1,
KERN_INFO
- "%s: zr36057_init() - initializing card[%d], zr=%p\n",
- ZR_DEVNAME(zr), zr->id, zr);
+ "%s: %s - initializing card[%d], zr=%p\n",
+ ZR_DEVNAME(zr), __func__, zr->id, zr);
/* default setup of all parameters which will persist between opens */
zr->user = 0;
@@ -1040,8 +1038,8 @@ zr36057_init (struct zoran *zr)
if (zr->timing == NULL) {
dprintk(1,
KERN_WARNING
- "%s: zr36057_init() - default TV standard not supported by hardware. PAL will be used.\n",
- ZR_DEVNAME(zr));
+ "%s: %s - default TV standard not supported by hardware. PAL will be used.\n",
+ ZR_DEVNAME(zr), __func__);
zr->norm = V4L2_STD_PAL;
zr->timing = zr->card.tvn[0];
}
@@ -1065,8 +1063,8 @@ zr36057_init (struct zoran *zr)
if (!zr->stat_com || !zr->video_dev) {
dprintk(1,
KERN_ERR
- "%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
- ZR_DEVNAME(zr));
+ "%s: %s - kmalloc (STAT_COM) failed\n",
+ ZR_DEVNAME(zr), __func__);
err = -ENOMEM;
goto exit_free;
}
@@ -1160,10 +1158,8 @@ zoran_setup_videocodec (struct zoran *zr,
m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL);
if (!m) {
- dprintk(1,
- KERN_ERR
- "%s: zoran_setup_videocodec() - no memory\n",
- ZR_DEVNAME(zr));
+ dprintk(1, KERN_ERR "%s: %s - no memory\n",
+ ZR_DEVNAME(zr), __func__);
return m;
}
@@ -1201,6 +1197,18 @@ zoran_setup_videocodec (struct zoran *zr,
return m;
}
+static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct zoran *zr = to_zoran(sd->v4l2_dev);
+
+ /* Bt819 needs to reset its FIFO buffer using #FRST pin and
+ LML33 card uses GPIO(7) for that. */
+ if (cmd == BT819_FIFO_RESET_LOW)
+ GPIO(zr, 7, 0);
+ else if (cmd == BT819_FIFO_RESET_HIGH)
+ GPIO(zr, 7, 1);
+}
+
/*
* Scan for a Buz card (actually for the PCI controller ZR36057),
* request the irq and map the io memory
@@ -1220,21 +1228,18 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
nr = zoran_num++;
if (nr >= BUZ_MAX) {
- dprintk(1,
- KERN_ERR
- "%s: driver limited to %d card(s) maximum\n",
+ dprintk(1, KERN_ERR "%s: driver limited to %d card(s) maximum\n",
ZORAN_NAME, BUZ_MAX);
return -ENOENT;
}
zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
if (!zr) {
- dprintk(1,
- KERN_ERR
- "%s: find_zr36057() - kzalloc failed\n",
- ZORAN_NAME);
+ dprintk(1, KERN_ERR "%s: %s - kzalloc failed\n",
+ ZORAN_NAME, __func__);
return -ENOMEM;
}
+ zr->v4l2_dev.notify = zoran_subdev_notify;
if (v4l2_device_register(&pdev->dev, &zr->v4l2_dev))
goto zr_free_mem;
zr->pci_dev = pdev;
@@ -1307,9 +1312,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
zr->zr36057_mem = pci_ioremap_bar(zr->pci_dev, 0);
if (!zr->zr36057_mem) {
- dprintk(1,
- KERN_ERR
- "%s: %s() - ioremap failed\n",
+ dprintk(1, KERN_ERR "%s: %s() - ioremap failed\n",
ZR_DEVNAME(zr), __func__);
goto zr_unreg;
}
@@ -1320,18 +1323,18 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
if (result == -EINVAL) {
dprintk(1,
KERN_ERR
- "%s: find_zr36057() - bad irq number or handler\n",
- ZR_DEVNAME(zr));
+ "%s: %s - bad irq number or handler\n",
+ ZR_DEVNAME(zr), __func__);
} else if (result == -EBUSY) {
dprintk(1,
KERN_ERR
- "%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n",
- ZR_DEVNAME(zr), zr->pci_dev->irq);
+ "%s: %s - IRQ %d busy, change your PnP config in BIOS\n",
+ ZR_DEVNAME(zr), __func__, zr->pci_dev->irq);
} else {
dprintk(1,
KERN_ERR
- "%s: find_zr36057() - can't assign irq, error code %d\n",
- ZR_DEVNAME(zr), result);
+ "%s: %s - can't assign irq, error code %d\n",
+ ZR_DEVNAME(zr), __func__, result);
}
goto zr_unmap;
}
@@ -1341,9 +1344,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
&latency);
need_latency = zr->revision > 1 ? 32 : 48;
if (latency != need_latency) {
- dprintk(2,
- KERN_INFO
- "%s: Changing PCI latency from %d to %d\n",
+ dprintk(2, KERN_INFO "%s: Changing PCI latency from %d to %d\n",
ZR_DEVNAME(zr), latency, need_latency);
pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
need_latency);
@@ -1355,10 +1356,8 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
ZR_DEVNAME(zr));
if (zoran_register_i2c(zr) < 0) {
- dprintk(1,
- KERN_ERR
- "%s: find_zr36057() - can't initialize i2c bus\n",
- ZR_DEVNAME(zr));
+ dprintk(1, KERN_ERR "%s: %s - can't initialize i2c bus\n",
+ ZR_DEVNAME(zr), __func__);
goto zr_free_irq;
}
@@ -1410,17 +1409,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
goto zr_unreg_i2c;
zr->codec = videocodec_attach(master_codec);
if (!zr->codec) {
- dprintk(1,
- KERN_ERR
- "%s: find_zr36057() - no codec found\n",
- ZR_DEVNAME(zr));
+ dprintk(1, KERN_ERR "%s: %s - no codec found\n",
+ ZR_DEVNAME(zr), __func__);
goto zr_free_codec;
}
if (zr->codec->type != zr->card.video_codec) {
- dprintk(1,
- KERN_ERR
- "%s: find_zr36057() - wrong codec\n",
- ZR_DEVNAME(zr));
+ dprintk(1, KERN_ERR "%s: %s - wrong codec\n",
+ ZR_DEVNAME(zr), __func__);
goto zr_detach_codec;
}
}
@@ -1430,17 +1425,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
goto zr_detach_codec;
zr->vfe = videocodec_attach(master_vfe);
if (!zr->vfe) {
- dprintk(1,
- KERN_ERR
- "%s: find_zr36057() - no VFE found\n",
- ZR_DEVNAME(zr));
+ dprintk(1, KERN_ERR "%s: %s - no VFE found\n",
+ ZR_DEVNAME(zr), __func__);
goto zr_free_vfe;
}
if (zr->vfe->type != zr->card.video_vfe) {
- dprintk(1,
- KERN_ERR
- "%s: find_zr36057() = wrong VFE\n",
- ZR_DEVNAME(zr));
+ dprintk(1, KERN_ERR "%s: %s = wrong VFE\n",
+ ZR_DEVNAME(zr), __func__);
goto zr_detach_vfe;
}
}
@@ -1448,8 +1439,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
/* take care of Natoma chipset and a revision 1 zr36057 */
if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
zr->jpg_buffers.need_contiguous = 1;
- dprintk(1,
- KERN_INFO
+ dprintk(1, KERN_INFO
"%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
ZR_DEVNAME(zr));
}
diff --git a/linux/drivers/media/video/zoran/zoran_device.c b/linux/drivers/media/video/zoran/zoran_device.c
index c2dfd4b67..54a04ea5c 100644
--- a/linux/drivers/media/video/zoran/zoran_device.c
+++ b/linux/drivers/media/video/zoran/zoran_device.c
@@ -536,12 +536,8 @@ zr36057_overlay (struct zoran *zr,
* and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
*/
-void
-write_overlay_mask (struct file *file,
- struct v4l2_clip *vp,
- int count)
+void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
u32 *mask;
@@ -1126,7 +1122,7 @@ zoran_feed_stat_com (struct zoran *zr)
if (!(zr->stat_com[i] & cpu_to_le32(1)))
break;
zr->stat_com[i] =
- cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+ cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
} else {
/* fill 2 stat_com entries */
i = ((zr->jpg_dma_head -
@@ -1134,9 +1130,9 @@ zoran_feed_stat_com (struct zoran *zr)
if (!(zr->stat_com[i] & cpu_to_le32(1)))
break;
zr->stat_com[i] =
- cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+ cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
zr->stat_com[i + 1] =
- cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
+ cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
}
zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA;
zr->jpg_dma_head++;
@@ -1156,7 +1152,7 @@ zoran_reap_stat_com (struct zoran *zr)
u32 stat_com;
unsigned int seq;
unsigned int dif;
- struct zoran_jpg_buffer *buffer;
+ struct zoran_buffer *buffer;
int frame;
/* In motion decompress we don't have a hardware frame counter,
@@ -1299,7 +1295,7 @@ error_handler (struct zoran *zr,
printk(KERN_INFO "stat_com frames:");
for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
- if (le32_to_cpu(zr->stat_com[j]) == zr->jpg_buffers.buffer[i].frag_tab_bus)
+ if (le32_to_cpu(zr->stat_com[j]) == zr->jpg_buffers.buffer[i].jpg.frag_tab_bus)
printk(KERN_CONT "% d->%d", j, i);
}
}
@@ -1443,7 +1439,7 @@ zoran_irq (int irq,
/* Buffer address */
- reg = zr->v4l_buffers.buffer[frame].fbuffer_bus;
+ reg = zr->v4l_buffers.buffer[frame].v4l.fbuffer_bus;
btwrite(reg, ZR36057_VDTR);
if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
reg += zr->v4l_settings.bytesperline;
@@ -1594,8 +1590,8 @@ zoran_init_hardware (struct zoran *zr)
route.input = zr->card.input[zr->input].muxsel;
decoder_call(zr, core, init, 0);
- decoder_s_std(zr, zr->norm);
- decoder_s_routing(zr, &route);
+ decoder_call(zr, tuner, s_std, zr->norm);
+ decoder_call(zr, video, s_routing, &route);
encoder_call(zr, core, init, 0);
encoder_call(zr, video, s_std_output, zr->norm);
@@ -1660,35 +1656,3 @@ zr36057_init_vfe (struct zoran *zr)
reg |= ZR36057_VDCR_Triton;
btwrite(reg, ZR36057_VDCR);
}
-
-/*
- * Interface to decoder and encoder chips using i2c bus
- */
-
-int decoder_s_std(struct zoran *zr, v4l2_std_id std)
-{
- int res;
-
- /* Bt819 needs to reset its FIFO buffer using #FRST pin and
- LML33 card uses GPIO(7) for that. */
- if (zr->card.type == LML33)
- GPIO(zr, 7, 0);
- res = decoder_call(zr, tuner, s_std, std);
- if (zr->card.type == LML33)
- GPIO(zr, 7, 1); /* Pull #FRST high. */
- return res;
-}
-
-int decoder_s_routing(struct zoran *zr, struct v4l2_routing *route)
-{
- int res;
-
- /* Bt819 needs to reset its FIFO buffer using #FRST pin and
- LML33 card uses GPIO(7) for that. */
- if (zr->card.type == LML33)
- GPIO(zr, 7, 0);
- res = decoder_call(zr, video, s_routing, route);
- if (zr->card.type == LML33)
- GPIO(zr, 7, 1); /* Pull #FRST high. */
- return res;
-}
diff --git a/linux/drivers/media/video/zoran/zoran_device.h b/linux/drivers/media/video/zoran/zoran_device.h
index 2eb645904..bf8c94d03 100644
--- a/linux/drivers/media/video/zoran/zoran_device.h
+++ b/linux/drivers/media/video/zoran/zoran_device.h
@@ -54,7 +54,7 @@ extern int jpeg_codec_reset(struct zoran *zr);
/* zr360x7 access to raw capture */
extern void zr36057_overlay(struct zoran *zr,
int on);
-extern void write_overlay_mask(struct file *file,
+extern void write_overlay_mask(struct zoran_fh *fh,
struct v4l2_clip *vp,
int count);
extern void zr36057_set_memgrab(struct zoran *zr,
@@ -98,7 +98,4 @@ extern int pass_through;
#define encoder_call(zr, o, f, args...) \
v4l2_subdev_call(zr->encoder, o, f, ##args)
-int decoder_s_std(struct zoran *zr, v4l2_std_id std);
-int decoder_s_routing(struct zoran *zr, struct v4l2_routing *route);
-
#endif /* __ZORAN_DEVICE_H__ */
diff --git a/linux/drivers/media/video/zoran/zoran_driver.c b/linux/drivers/media/video/zoran/zoran_driver.c
index 7ddbdf37d..c702ea0fe 100644
--- a/linux/drivers/media/video/zoran/zoran_driver.c
+++ b/linux/drivers/media/video/zoran/zoran_driver.c
@@ -59,7 +59,7 @@
#include <linux/spinlock.h>
-#include <linux/videodev2.h>
+#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include "videocodec.h"
@@ -163,10 +163,6 @@ const struct zoran_format zoran_formats[] = {
};
#define NUM_FORMATS ARRAY_SIZE(zoran_formats)
-static int lock_norm; /* 0 = default 1 = Don't change TV standard (norm) */
-module_param(lock_norm, int, 0644);
-MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
-
/* small helper function for calculating buffersizes for v4l2
* we calculate the nearest higher power-of-two, which
* will be the recommended buffersize */
@@ -191,8 +187,26 @@ zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
}
/* forward references */
-static void v4l_fbuffer_free(struct file *file);
-static void jpg_fbuffer_free(struct file *file);
+static void v4l_fbuffer_free(struct zoran_fh *fh);
+static void jpg_fbuffer_free(struct zoran_fh *fh);
+
+/* Set mapping mode */
+static void map_mode_raw(struct zoran_fh *fh)
+{
+ fh->map_mode = ZORAN_MAP_MODE_RAW;
+ fh->buffers.buffer_size = v4l_bufsize;
+ fh->buffers.num_buffers = v4l_nbufs;
+}
+static void map_mode_jpg(struct zoran_fh *fh, int play)
+{
+ fh->map_mode = play ? ZORAN_MAP_MODE_JPG_PLAY : ZORAN_MAP_MODE_JPG_REC;
+ fh->buffers.buffer_size = jpg_bufsize;
+ fh->buffers.num_buffers = jpg_nbufs;
+}
+static inline const char *mode_name(enum zoran_map_mode mode)
+{
+ return mode == ZORAN_MAP_MODE_RAW ? "V4L" : "JPG";
+}
/*
* Allocate the V4L grab buffers
@@ -200,75 +214,70 @@ static void jpg_fbuffer_free(struct file *file);
* These have to be pysically contiguous.
*/
-static int
-v4l_fbuffer_alloc (struct file *file)
+static int v4l_fbuffer_alloc(struct zoran_fh *fh)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
int i, off;
unsigned char *mem;
- for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
- if (fh->v4l_buffers.buffer[i].fbuffer)
+ for (i = 0; i < fh->buffers.num_buffers; i++) {
+ if (fh->buffers.buffer[i].v4l.fbuffer)
dprintk(2,
KERN_WARNING
- "%s: v4l_fbuffer_alloc() - buffer %d already allocated!?\n",
- ZR_DEVNAME(zr), i);
+ "%s: %s - buffer %d already allocated!?\n",
+ ZR_DEVNAME(zr), __func__, i);
//udelay(20);
- mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
+ mem = kmalloc(fh->buffers.buffer_size,
+ GFP_KERNEL | __GFP_NOWARN);
if (!mem) {
dprintk(1,
KERN_ERR
- "%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n",
- ZR_DEVNAME(zr), i);
- v4l_fbuffer_free(file);
+ "%s: %s - kmalloc for V4L buf %d failed\n",
+ ZR_DEVNAME(zr), __func__, i);
+ v4l_fbuffer_free(fh);
return -ENOBUFS;
}
- fh->v4l_buffers.buffer[i].fbuffer = mem;
- fh->v4l_buffers.buffer[i].fbuffer_phys =
- virt_to_phys(mem);
- fh->v4l_buffers.buffer[i].fbuffer_bus =
- virt_to_bus(mem);
- for (off = 0; off < fh->v4l_buffers.buffer_size;
+ fh->buffers.buffer[i].v4l.fbuffer = mem;
+ fh->buffers.buffer[i].v4l.fbuffer_phys = virt_to_phys(mem);
+ fh->buffers.buffer[i].v4l.fbuffer_bus = virt_to_bus(mem);
+ for (off = 0; off < fh->buffers.buffer_size;
off += PAGE_SIZE)
SetPageReserved(virt_to_page(mem + off));
dprintk(4,
KERN_INFO
- "%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n",
- ZR_DEVNAME(zr), i, (unsigned long) mem,
- virt_to_bus(mem));
+ "%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n",
+ ZR_DEVNAME(zr), __func__, i, (unsigned long) mem,
+ (unsigned long long)virt_to_bus(mem));
}
- fh->v4l_buffers.allocated = 1;
+ fh->buffers.allocated = 1;
return 0;
}
/* free the V4L grab buffers */
-static void
-v4l_fbuffer_free (struct file *file)
+static void v4l_fbuffer_free(struct zoran_fh *fh)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
int i, off;
unsigned char *mem;
- dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr));
+ dprintk(4, KERN_INFO "%s: %s\n", ZR_DEVNAME(zr), __func__);
- for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
- if (!fh->v4l_buffers.buffer[i].fbuffer)
+ for (i = 0; i < fh->buffers.num_buffers; i++) {
+ if (!fh->buffers.buffer[i].v4l.fbuffer)
continue;
- mem = fh->v4l_buffers.buffer[i].fbuffer;
- for (off = 0; off < fh->v4l_buffers.buffer_size;
+ mem = fh->buffers.buffer[i].v4l.fbuffer;
+ for (off = 0; off < fh->buffers.buffer_size;
off += PAGE_SIZE)
ClearPageReserved(virt_to_page(mem + off));
- kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
- fh->v4l_buffers.buffer[i].fbuffer = NULL;
+ kfree(fh->buffers.buffer[i].v4l.fbuffer);
+ fh->buffers.buffer[i].v4l.fbuffer = NULL;
}
- fh->v4l_buffers.allocated = 0;
+ fh->buffers.allocated = 0;
}
/*
@@ -299,140 +308,128 @@ v4l_fbuffer_free (struct file *file)
* and fragment buffers are not little-endian.
*/
-static int
-jpg_fbuffer_alloc (struct file *file)
+static int jpg_fbuffer_alloc(struct zoran_fh *fh)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
int i, j, off;
- unsigned long mem;
+ u8 *mem;
- for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
- if (fh->jpg_buffers.buffer[i].frag_tab)
+ for (i = 0; i < fh->buffers.num_buffers; i++) {
+ if (fh->buffers.buffer[i].jpg.frag_tab)
dprintk(2,
KERN_WARNING
- "%s: jpg_fbuffer_alloc() - buffer %d already allocated!?\n",
- ZR_DEVNAME(zr), i);
+ "%s: %s - buffer %d already allocated!?\n",
+ ZR_DEVNAME(zr), __func__, i);
/* Allocate fragment table for this buffer */
- mem = get_zeroed_page(GFP_KERNEL);
+ mem = (void *)get_zeroed_page(GFP_KERNEL);
if (mem == 0) {
dprintk(1,
KERN_ERR
- "%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n",
- ZR_DEVNAME(zr), i);
- jpg_fbuffer_free(file);
+ "%s: %s - get_zeroed_page (frag_tab) failed for buffer %d\n",
+ ZR_DEVNAME(zr), __func__, i);
+ jpg_fbuffer_free(fh);
return -ENOBUFS;
}
- fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem;
- fh->jpg_buffers.buffer[i].frag_tab_bus =
- virt_to_bus((void *) mem);
-
- //if (alloc_contig) {
- if (fh->jpg_buffers.need_contiguous) {
- mem =
- (unsigned long) kmalloc(fh->jpg_buffers.
- buffer_size,
- GFP_KERNEL);
- if (mem == 0) {
+ fh->buffers.buffer[i].jpg.frag_tab = (__le32 *)mem;
+ fh->buffers.buffer[i].jpg.frag_tab_bus = virt_to_bus(mem);
+
+ if (fh->buffers.need_contiguous) {
+ mem = kmalloc(fh->buffers.buffer_size, GFP_KERNEL);
+ if (mem == NULL) {
dprintk(1,
KERN_ERR
- "%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n",
- ZR_DEVNAME(zr), i);
- jpg_fbuffer_free(file);
+ "%s: %s - kmalloc failed for buffer %d\n",
+ ZR_DEVNAME(zr), __func__, i);
+ jpg_fbuffer_free(fh);
return -ENOBUFS;
}
- fh->jpg_buffers.buffer[i].frag_tab[0] =
- cpu_to_le32(virt_to_bus((void *) mem));
- fh->jpg_buffers.buffer[i].frag_tab[1] =
- cpu_to_le32(((fh->jpg_buffers.buffer_size / 4) << 1) | 1);
- for (off = 0; off < fh->jpg_buffers.buffer_size;
- off += PAGE_SIZE)
+ fh->buffers.buffer[i].jpg.frag_tab[0] =
+ cpu_to_le32(virt_to_bus(mem));
+ fh->buffers.buffer[i].jpg.frag_tab[1] =
+ cpu_to_le32((fh->buffers.buffer_size >> 1) | 1);
+ for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
SetPageReserved(virt_to_page(mem + off));
} else {
/* jpg_bufsize is already page aligned */
- for (j = 0;
- j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
- j++) {
- mem = get_zeroed_page(GFP_KERNEL);
- if (mem == 0) {
+ for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
+ mem = (void *)get_zeroed_page(GFP_KERNEL);
+ if (mem == NULL) {
dprintk(1,
KERN_ERR
- "%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n",
- ZR_DEVNAME(zr), i);
- jpg_fbuffer_free(file);
+ "%s: %s - get_zeroed_page failed for buffer %d\n",
+ ZR_DEVNAME(zr), __func__, i);
+ jpg_fbuffer_free(fh);
return -ENOBUFS;
}
- fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
- cpu_to_le32(virt_to_bus((void *) mem));
- fh->jpg_buffers.buffer[i].frag_tab[2 * j +
- 1] =
- cpu_to_le32((PAGE_SIZE / 4) << 1);
+ fh->buffers.buffer[i].jpg.frag_tab[2 * j] =
+ cpu_to_le32(virt_to_bus(mem));
+ fh->buffers.buffer[i].jpg.frag_tab[2 * j + 1] =
+ cpu_to_le32((PAGE_SIZE >> 2) << 1);
SetPageReserved(virt_to_page(mem));
}
- fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1);
+ fh->buffers.buffer[i].jpg.frag_tab[2 * j - 1] |= cpu_to_le32(1);
}
}
dprintk(4,
- KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n",
- ZR_DEVNAME(zr),
- (fh->jpg_buffers.num_buffers *
- fh->jpg_buffers.buffer_size) >> 10);
+ KERN_DEBUG "%s: %s - %d KB allocated\n",
+ ZR_DEVNAME(zr), __func__,
+ (fh->buffers.num_buffers * fh->buffers.buffer_size) >> 10);
- fh->jpg_buffers.allocated = 1;
+ fh->buffers.allocated = 1;
return 0;
}
/* free the MJPEG grab buffers */
-static void
-jpg_fbuffer_free (struct file *file)
+static void jpg_fbuffer_free(struct zoran_fh *fh)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
int i, j, off;
unsigned char *mem;
__le32 frag_tab;
+ struct zoran_buffer *buffer;
- dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr));
+ dprintk(4, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
- for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
- if (!fh->jpg_buffers.buffer[i].frag_tab)
+ for (i = 0, buffer = &fh->buffers.buffer[0];
+ i < fh->buffers.num_buffers; i++, buffer++) {
+ if (!buffer->jpg.frag_tab)
continue;
- if (fh->jpg_buffers.need_contiguous) {
- frag_tab = fh->jpg_buffers.buffer[i].frag_tab[0];
+ if (fh->buffers.need_contiguous) {
+ frag_tab = buffer->jpg.frag_tab[0];
if (frag_tab) {
- mem = (unsigned char *)bus_to_virt(le32_to_cpu(frag_tab));
- for (off = 0; off < fh->jpg_buffers.buffer_size; off += PAGE_SIZE)
+ mem = bus_to_virt(le32_to_cpu(frag_tab));
+ for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
ClearPageReserved(virt_to_page(mem + off));
kfree(mem);
- fh->jpg_buffers.buffer[i].frag_tab[0] = 0;
- fh->jpg_buffers.buffer[i].frag_tab[1] = 0;
+ buffer->jpg.frag_tab[0] = 0;
+ buffer->jpg.frag_tab[1] = 0;
}
} else {
- for (j = 0; j < fh->jpg_buffers.buffer_size / PAGE_SIZE; j++) {
- frag_tab = fh->jpg_buffers.buffer[i].frag_tab[2 * j];
+ for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
+ frag_tab = buffer->jpg.frag_tab[2 * j];
if (!frag_tab)
break;
ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab))));
free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab)));
- fh->jpg_buffers.buffer[i].frag_tab[2 * j] = 0;
- fh->jpg_buffers.buffer[i].frag_tab[2 * j + 1] = 0;
+ buffer->jpg.frag_tab[2 * j] = 0;
+ buffer->jpg.frag_tab[2 * j + 1] = 0;
}
}
- free_page((unsigned long)fh->jpg_buffers.buffer[i].frag_tab);
- fh->jpg_buffers.buffer[i].frag_tab = NULL;
+ free_page((unsigned long)buffer->jpg.frag_tab);
+ buffer->jpg.frag_tab = NULL;
}
- fh->jpg_buffers.allocated = 0;
+ fh->buffers.allocated = 0;
}
/*
@@ -440,12 +437,11 @@ jpg_fbuffer_free (struct file *file)
*/
static int
-zoran_v4l_set_format (struct file *file,
+zoran_v4l_set_format (struct zoran_fh *fh,
int width,
int height,
const struct zoran_format *format)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
int bpp;
@@ -455,19 +451,19 @@ zoran_v4l_set_format (struct file *file,
height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) {
dprintk(1,
KERN_ERR
- "%s: v4l_set_format() - wrong frame size (%dx%d)\n",
- ZR_DEVNAME(zr), width, height);
+ "%s: %s - wrong frame size (%dx%d)\n",
+ ZR_DEVNAME(zr), __func__, width, height);
return -EINVAL;
}
bpp = (format->depth + 7) / 8;
/* Check against available buffer size */
- if (height * width * bpp > fh->v4l_buffers.buffer_size) {
+ if (height * width * bpp > fh->buffers.buffer_size) {
dprintk(1,
KERN_ERR
- "%s: v4l_set_format() - video buffer size (%d kB) is too small\n",
- ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10);
+ "%s: %s - video buffer size (%d kB) is too small\n",
+ ZR_DEVNAME(zr), __func__, fh->buffers.buffer_size >> 10);
return -EINVAL;
}
@@ -476,8 +472,8 @@ zoran_v4l_set_format (struct file *file,
if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
dprintk(1,
KERN_ERR
- "%s: v4l_set_format() - wrong frame alignment\n",
- ZR_DEVNAME(zr));
+ "%s: %s - wrong frame alignment\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
@@ -489,43 +485,40 @@ zoran_v4l_set_format (struct file *file,
return 0;
}
-static int
-zoran_v4l_queue_frame (struct file *file,
- int num)
+static int zoran_v4l_queue_frame(struct zoran_fh *fh, int num)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
unsigned long flags;
int res = 0;
- if (!fh->v4l_buffers.allocated) {
+ if (!fh->buffers.allocated) {
dprintk(1,
KERN_ERR
- "%s: v4l_queue_frame() - buffers not yet allocated\n",
- ZR_DEVNAME(zr));
+ "%s: %s - buffers not yet allocated\n",
+ ZR_DEVNAME(zr), __func__);
res = -ENOMEM;
}
/* No grabbing outside the buffer range! */
- if (num >= fh->v4l_buffers.num_buffers || num < 0) {
+ if (num >= fh->buffers.num_buffers || num < 0) {
dprintk(1,
KERN_ERR
- "%s: v4l_queue_frame() - buffer %d is out of range\n",
- ZR_DEVNAME(zr), num);
+ "%s: %s - buffer %d is out of range\n",
+ ZR_DEVNAME(zr), __func__, num);
res = -EINVAL;
}
spin_lock_irqsave(&zr->spinlock, flags);
- if (fh->v4l_buffers.active == ZORAN_FREE) {
+ if (fh->buffers.active == ZORAN_FREE) {
if (zr->v4l_buffers.active == ZORAN_FREE) {
- zr->v4l_buffers = fh->v4l_buffers;
- fh->v4l_buffers.active = ZORAN_ACTIVE;
+ zr->v4l_buffers = fh->buffers;
+ fh->buffers.active = ZORAN_ACTIVE;
} else {
dprintk(1,
KERN_ERR
- "%s: v4l_queue_frame() - another session is already capturing\n",
- ZR_DEVNAME(zr));
+ "%s: %s - another session is already capturing\n",
+ ZR_DEVNAME(zr), __func__);
res = -EBUSY;
}
}
@@ -536,7 +529,7 @@ zoran_v4l_queue_frame (struct file *file,
default:
case BUZ_STATE_PEND:
if (zr->v4l_buffers.active == ZORAN_FREE) {
- fh->v4l_buffers.active = ZORAN_FREE;
+ fh->buffers.active = ZORAN_FREE;
zr->v4l_buffers.allocated = 0;
}
res = -EBUSY; /* what are you doing? */
@@ -544,19 +537,17 @@ zoran_v4l_queue_frame (struct file *file,
case BUZ_STATE_DONE:
dprintk(2,
KERN_WARNING
- "%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n",
- ZR_DEVNAME(zr), num);
+ "%s: %s - queueing buffer %d in state DONE!?\n",
+ ZR_DEVNAME(zr), __func__, num);
case BUZ_STATE_USER:
/* since there is at least one unused buffer there's room for at least
* one more pend[] entry */
- zr->v4l_pend[zr->v4l_pend_head++ &
- V4L_MASK_FRAME] = num;
+ zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = num;
zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND;
zr->v4l_buffers.buffer[num].bs.length =
fh->v4l_settings.bytesperline *
zr->v4l_settings.height;
- fh->v4l_buffers.buffer[num] =
- zr->v4l_buffers.buffer[num];
+ fh->buffers.buffer[num] = zr->v4l_buffers.buffer[num];
break;
}
}
@@ -564,7 +555,7 @@ zoran_v4l_queue_frame (struct file *file,
spin_unlock_irqrestore(&zr->spinlock, flags);
if (!res && zr->v4l_buffers.active == ZORAN_FREE)
- zr->v4l_buffers.active = fh->v4l_buffers.active;
+ zr->v4l_buffers.active = fh->buffers.active;
return res;
}
@@ -573,27 +564,24 @@ zoran_v4l_queue_frame (struct file *file,
* Sync on a V4L buffer
*/
-static int
-v4l_sync (struct file *file,
- int frame)
+static int v4l_sync(struct zoran_fh *fh, int frame)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
unsigned long flags;
- if (fh->v4l_buffers.active == ZORAN_FREE) {
+ if (fh->buffers.active == ZORAN_FREE) {
dprintk(1,
KERN_ERR
- "%s: v4l_sync() - no grab active for this session\n",
- ZR_DEVNAME(zr));
+ "%s: %s - no grab active for this session\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
/* check passed-in frame number */
- if (frame >= fh->v4l_buffers.num_buffers || frame < 0) {
+ if (frame >= fh->buffers.num_buffers || frame < 0) {
dprintk(1,
- KERN_ERR "%s: v4l_sync() - frame %d is invalid\n",
- ZR_DEVNAME(zr), frame);
+ KERN_ERR "%s: %s - frame %d is invalid\n",
+ ZR_DEVNAME(zr), __func__, frame);
return -EINVAL;
}
@@ -601,15 +589,14 @@ v4l_sync (struct file *file,
if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) {
dprintk(1,
KERN_ERR
- "%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n",
- ZR_DEVNAME(zr));
+ "%s: %s - attempt to sync on a buffer which was not queued?\n",
+ ZR_DEVNAME(zr), __func__);
return -EPROTO;
}
/* wait on this buffer to get ready */
if (!wait_event_interruptible_timeout(zr->v4l_capq,
- (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND),
- 10*HZ))
+ (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), 10*HZ))
return -ETIME;
if (signal_pending(current))
return -ERESTARTSYS;
@@ -617,11 +604,11 @@ v4l_sync (struct file *file,
/* buffer should now be in BUZ_STATE_DONE */
if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE)
dprintk(2,
- KERN_ERR "%s: v4l_sync() - internal state error\n",
- ZR_DEVNAME(zr));
+ KERN_ERR "%s: %s - internal state error\n",
+ ZR_DEVNAME(zr), __func__);
zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER;
- fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
+ fh->buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
spin_lock_irqsave(&zr->spinlock, flags);
@@ -629,8 +616,7 @@ v4l_sync (struct file *file,
if (zr->v4l_pend_tail == zr->v4l_pend_head) {
zr36057_set_memgrab(zr, 0);
if (zr->v4l_buffers.active == ZORAN_ACTIVE) {
- fh->v4l_buffers.active = zr->v4l_buffers.active =
- ZORAN_FREE;
+ fh->buffers.active = zr->v4l_buffers.active = ZORAN_FREE;
zr->v4l_buffers.allocated = 0;
}
}
@@ -644,31 +630,28 @@ v4l_sync (struct file *file,
* Queue a MJPEG buffer for capture/playback
*/
-static int
-zoran_jpg_queue_frame (struct file *file,
- int num,
- enum zoran_codec_mode mode)
+static int zoran_jpg_queue_frame(struct zoran_fh *fh, int num,
+ enum zoran_codec_mode mode)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
unsigned long flags;
int res = 0;
/* Check if buffers are allocated */
- if (!fh->jpg_buffers.allocated) {
+ if (!fh->buffers.allocated) {
dprintk(1,
KERN_ERR
- "%s: jpg_queue_frame() - buffers not yet allocated\n",
- ZR_DEVNAME(zr));
+ "%s: %s - buffers not yet allocated\n",
+ ZR_DEVNAME(zr), __func__);
return -ENOMEM;
}
/* No grabbing outside the buffer range! */
- if (num >= fh->jpg_buffers.num_buffers || num < 0) {
+ if (num >= fh->buffers.num_buffers || num < 0) {
dprintk(1,
KERN_ERR
- "%s: jpg_queue_frame() - buffer %d out of range\n",
- ZR_DEVNAME(zr), num);
+ "%s: %s - buffer %d out of range\n",
+ ZR_DEVNAME(zr), __func__, num);
return -EINVAL;
}
@@ -679,20 +662,20 @@ zoran_jpg_queue_frame (struct file *file,
/* wrong codec mode active - invalid */
dprintk(1,
KERN_ERR
- "%s: jpg_queue_frame() - codec in wrong mode\n",
- ZR_DEVNAME(zr));
+ "%s: %s - codec in wrong mode\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
- if (fh->jpg_buffers.active == ZORAN_FREE) {
+ if (fh->buffers.active == ZORAN_FREE) {
if (zr->jpg_buffers.active == ZORAN_FREE) {
- zr->jpg_buffers = fh->jpg_buffers;
- fh->jpg_buffers.active = ZORAN_ACTIVE;
+ zr->jpg_buffers = fh->buffers;
+ fh->buffers.active = ZORAN_ACTIVE;
} else {
dprintk(1,
KERN_ERR
- "%s: jpg_queue_frame() - another session is already capturing\n",
- ZR_DEVNAME(zr));
+ "%s: %s - another session is already capturing\n",
+ ZR_DEVNAME(zr), __func__);
res = -EBUSY;
}
}
@@ -709,23 +692,21 @@ zoran_jpg_queue_frame (struct file *file,
case BUZ_STATE_DONE:
dprintk(2,
KERN_WARNING
- "%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n",
- ZR_DEVNAME(zr));
+ "%s: %s - queing frame in BUZ_STATE_DONE state!?\n",
+ ZR_DEVNAME(zr), __func__);
case BUZ_STATE_USER:
/* since there is at least one unused buffer there's room for at
*least one more pend[] entry */
- zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] =
- num;
+ zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = num;
zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND;
- fh->jpg_buffers.buffer[num] =
- zr->jpg_buffers.buffer[num];
+ fh->buffers.buffer[num] = zr->jpg_buffers.buffer[num];
zoran_feed_stat_com(zr);
break;
default:
case BUZ_STATE_DMA:
case BUZ_STATE_PEND:
if (zr->jpg_buffers.active == ZORAN_FREE) {
- fh->jpg_buffers.active = ZORAN_FREE;
+ fh->buffers.active = ZORAN_FREE;
zr->jpg_buffers.allocated = 0;
}
res = -EBUSY; /* what are you doing? */
@@ -735,47 +716,41 @@ zoran_jpg_queue_frame (struct file *file,
spin_unlock_irqrestore(&zr->spinlock, flags);
- if (!res && zr->jpg_buffers.active == ZORAN_FREE) {
- zr->jpg_buffers.active = fh->jpg_buffers.active;
- }
+ if (!res && zr->jpg_buffers.active == ZORAN_FREE)
+ zr->jpg_buffers.active = fh->buffers.active;
return res;
}
-static int
-jpg_qbuf (struct file *file,
- int frame,
- enum zoran_codec_mode mode)
+static int jpg_qbuf(struct zoran_fh *fh, int frame, enum zoran_codec_mode mode)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
int res = 0;
/* Does the user want to stop streaming? */
if (frame < 0) {
if (zr->codec_mode == mode) {
- if (fh->jpg_buffers.active == ZORAN_FREE) {
+ if (fh->buffers.active == ZORAN_FREE) {
dprintk(1,
KERN_ERR
- "%s: jpg_qbuf(-1) - session not active\n",
- ZR_DEVNAME(zr));
+ "%s: %s(-1) - session not active\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
- fh->jpg_buffers.active = zr->jpg_buffers.active =
- ZORAN_FREE;
+ fh->buffers.active = zr->jpg_buffers.active = ZORAN_FREE;
zr->jpg_buffers.allocated = 0;
zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
return 0;
} else {
dprintk(1,
KERN_ERR
- "%s: jpg_qbuf() - stop streaming but not in streaming mode\n",
- ZR_DEVNAME(zr));
+ "%s: %s - stop streaming but not in streaming mode\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
}
- if ((res = zoran_jpg_queue_frame(file, frame, mode)))
+ if ((res = zoran_jpg_queue_frame(fh, frame, mode)))
return res;
/* Start the jpeg codec when the first frame is queued */
@@ -789,28 +764,25 @@ jpg_qbuf (struct file *file,
* Sync on a MJPEG buffer
*/
-static int
-jpg_sync (struct file *file,
- struct zoran_sync *bs)
+static int jpg_sync(struct zoran_fh *fh, struct zoran_sync *bs)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
unsigned long flags;
int frame;
- if (fh->jpg_buffers.active == ZORAN_FREE) {
+ if (fh->buffers.active == ZORAN_FREE) {
dprintk(1,
KERN_ERR
- "%s: jpg_sync() - capture is not currently active\n",
- ZR_DEVNAME(zr));
+ "%s: %s - capture is not currently active\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
dprintk(1,
KERN_ERR
- "%s: jpg_sync() - codec not in streaming mode\n",
- ZR_DEVNAME(zr));
+ "%s: %s - codec not in streaming mode\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
if (!wait_event_interruptible_timeout(zr->jpg_capq,
@@ -825,8 +797,8 @@ jpg_sync (struct file *file,
sizeof(isr), &isr);
dprintk(1,
KERN_ERR
- "%s: jpg_sync() - timeout: codec isr=0x%02x\n",
- ZR_DEVNAME(zr), isr);
+ "%s: %s - timeout: codec isr=0x%02x\n",
+ ZR_DEVNAME(zr), __func__, isr);
return -ETIME;
@@ -844,28 +816,26 @@ jpg_sync (struct file *file,
/* buffer should now be in BUZ_STATE_DONE */
if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
dprintk(2,
- KERN_ERR "%s: jpg_sync() - internal state error\n",
- ZR_DEVNAME(zr));
+ KERN_ERR "%s: %s - internal state error\n",
+ ZR_DEVNAME(zr), __func__);
*bs = zr->jpg_buffers.buffer[frame].bs;
bs->frame = frame;
zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER;
- fh->jpg_buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
+ fh->buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
spin_unlock_irqrestore(&zr->spinlock, flags);
return 0;
}
-static void
-zoran_open_init_session (struct file *file)
+static void zoran_open_init_session(struct zoran_fh *fh)
{
int i;
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
/* Per default, map the V4L Buffers */
- fh->map_mode = ZORAN_MAP_MODE_RAW;
+ map_mode_raw(fh);
/* take over the card's current settings */
fh->overlay_settings = zr->overlay_settings;
@@ -875,38 +845,21 @@ zoran_open_init_session (struct file *file)
/* v4l settings */
fh->v4l_settings = zr->v4l_settings;
-
- /* v4l_buffers */
- memset(&fh->v4l_buffers, 0, sizeof(struct zoran_v4l_struct));
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- fh->v4l_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */
- fh->v4l_buffers.buffer[i].bs.frame = i;
- }
- fh->v4l_buffers.allocated = 0;
- fh->v4l_buffers.active = ZORAN_FREE;
- fh->v4l_buffers.buffer_size = v4l_bufsize;
- fh->v4l_buffers.num_buffers = v4l_nbufs;
-
/* jpg settings */
fh->jpg_settings = zr->jpg_settings;
- /* jpg_buffers */
- memset(&fh->jpg_buffers, 0, sizeof(struct zoran_jpg_struct));
- for (i = 0; i < BUZ_MAX_FRAME; i++) {
- fh->jpg_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */
- fh->jpg_buffers.buffer[i].bs.frame = i;
+ /* buffers */
+ memset(&fh->buffers, 0, sizeof(fh->buffers));
+ for (i = 0; i < MAX_FRAME; i++) {
+ fh->buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */
+ fh->buffers.buffer[i].bs.frame = i;
}
- fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous;
- fh->jpg_buffers.allocated = 0;
- fh->jpg_buffers.active = ZORAN_FREE;
- fh->jpg_buffers.buffer_size = jpg_bufsize;
- fh->jpg_buffers.num_buffers = jpg_nbufs;
+ fh->buffers.allocated = 0;
+ fh->buffers.active = ZORAN_FREE;
}
-static void
-zoran_close_end_session (struct file *file)
+static void zoran_close_end_session(struct zoran_fh *fh)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
/* overlay */
@@ -918,33 +871,33 @@ zoran_close_end_session (struct file *file)
zr->overlay_mask = NULL;
}
- /* v4l capture */
- if (fh->v4l_buffers.active != ZORAN_FREE) {
- unsigned long flags;
+ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+ /* v4l capture */
+ if (fh->buffers.active != ZORAN_FREE) {
+ unsigned long flags;
- spin_lock_irqsave(&zr->spinlock, flags);
- zr36057_set_memgrab(zr, 0);
- zr->v4l_buffers.allocated = 0;
- zr->v4l_buffers.active = fh->v4l_buffers.active =
- ZORAN_FREE;
- spin_unlock_irqrestore(&zr->spinlock, flags);
- }
+ spin_lock_irqsave(&zr->spinlock, flags);
+ zr36057_set_memgrab(zr, 0);
+ zr->v4l_buffers.allocated = 0;
+ zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+ }
- /* v4l buffers */
- if (fh->v4l_buffers.allocated)
- v4l_fbuffer_free(file);
+ /* v4l buffers */
+ if (fh->buffers.allocated)
+ v4l_fbuffer_free(fh);
+ } else {
+ /* jpg capture */
+ if (fh->buffers.active != ZORAN_FREE) {
+ zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+ zr->jpg_buffers.allocated = 0;
+ zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
+ }
- /* jpg capture */
- if (fh->jpg_buffers.active != ZORAN_FREE) {
- zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
- zr->jpg_buffers.allocated = 0;
- zr->jpg_buffers.active = fh->jpg_buffers.active =
- ZORAN_FREE;
+ /* jpg buffers */
+ if (fh->buffers.allocated)
+ jpg_fbuffer_free(fh);
}
-
- /* jpg buffers */
- if (fh->jpg_buffers.allocated)
- jpg_fbuffer_free(file);
}
/*
@@ -957,8 +910,8 @@ static int zoran_open(struct file *file)
struct zoran_fh *fh;
int res, first_open = 0;
- dprintk(2, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n",
- ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user + 1);
+ dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n",
+ ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1);
lock_kernel();
@@ -974,8 +927,8 @@ static int zoran_open(struct file *file)
if (!fh) {
dprintk(1,
KERN_ERR
- "%s: zoran_open() - allocation of zoran_fh failed\n",
- ZR_DEVNAME(zr));
+ "%s: %s - allocation of zoran_fh failed\n",
+ ZR_DEVNAME(zr), __func__);
res = -ENOMEM;
goto fail_unlock;
}
@@ -986,8 +939,8 @@ static int zoran_open(struct file *file)
if (!fh->overlay_mask) {
dprintk(1,
KERN_ERR
- "%s: zoran_open() - allocation of overlay_mask failed\n",
- ZR_DEVNAME(zr));
+ "%s: %s - allocation of overlay_mask failed\n",
+ ZR_DEVNAME(zr), __func__);
res = -ENOMEM;
goto fail_fh;
}
@@ -1009,7 +962,7 @@ static int zoran_open(struct file *file)
/* set file_ops stuff */
file->private_data = fh;
fh->zr = zr;
- zoran_open_init_session(file);
+ zoran_open_init_session(fh);
unlock_kernel();
return 0;
@@ -1031,14 +984,14 @@ zoran_close(struct file *file)
struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
- dprintk(2, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n",
- ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user - 1);
+ dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(+)=%d\n",
+ ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user - 1);
/* kernel locks (fs/device.c), so don't do that ourselves
* (prevents deadlocks) */
/*mutex_lock(&zr->resource_lock);*/
- zoran_close_end_session(file);
+ zoran_close_end_session(fh);
if (zr->user-- == 1) { /* Last process */
/* Clean up JPEG process */
@@ -1077,7 +1030,7 @@ zoran_close(struct file *file)
kfree(fh->overlay_mask);
kfree(fh);
- dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr));
+ dprintk(4, KERN_INFO "%s: %s done\n", ZR_DEVNAME(zr), __func__);
return 0;
}
@@ -1105,15 +1058,13 @@ zoran_write (struct file *file,
return -EINVAL;
}
-static int
-setup_fbuffer (struct file *file,
+static int setup_fbuffer(struct zoran_fh *fh,
void *base,
const struct zoran_format *fmt,
int width,
int height,
int bytesperline)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
/* (Ronald) v4l/v4l2 guidelines */
@@ -1141,8 +1092,8 @@ setup_fbuffer (struct file *file,
* friendly and silently do as if nothing went wrong */
dprintk(3,
KERN_ERR
- "%s: setup_fbuffer() - forced overlay turnoff because framebuffer changed\n",
- ZR_DEVNAME(zr));
+ "%s: %s - forced overlay turnoff because framebuffer changed\n",
+ ZR_DEVNAME(zr), __func__);
zr36057_overlay(zr, 0);
}
#endif
@@ -1150,22 +1101,22 @@ setup_fbuffer (struct file *file,
if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) {
dprintk(1,
KERN_ERR
- "%s: setup_fbuffer() - no valid overlay format given\n",
- ZR_DEVNAME(zr));
+ "%s: %s - no valid overlay format given\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
if (height <= 0 || width <= 0 || bytesperline <= 0) {
dprintk(1,
KERN_ERR
- "%s: setup_fbuffer() - invalid height/width/bpl value (%d|%d|%d)\n",
- ZR_DEVNAME(zr), width, height, bytesperline);
+ "%s: %s - invalid height/width/bpl value (%d|%d|%d)\n",
+ ZR_DEVNAME(zr), __func__, width, height, bytesperline);
return -EINVAL;
}
if (bytesperline & 3) {
dprintk(1,
KERN_ERR
- "%s: setup_fbuffer() - bytesperline (%d) must be 4-byte aligned\n",
- ZR_DEVNAME(zr), bytesperline);
+ "%s: %s - bytesperline (%d) must be 4-byte aligned\n",
+ ZR_DEVNAME(zr), __func__, bytesperline);
return -EINVAL;
}
@@ -1183,17 +1134,9 @@ setup_fbuffer (struct file *file,
}
-static int
-setup_window (struct file *file,
- int x,
- int y,
- int width,
- int height,
- struct v4l2_clip __user *clips,
- int clipcount,
- void __user *bitmap)
+static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height,
+ struct v4l2_clip __user *clips, int clipcount, void __user *bitmap)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
struct v4l2_clip *vcp = NULL;
int on, end;
@@ -1202,16 +1145,16 @@ setup_window (struct file *file,
if (!zr->vbuf_base) {
dprintk(1,
KERN_ERR
- "%s: setup_window() - frame buffer has to be set first\n",
- ZR_DEVNAME(zr));
+ "%s: %s - frame buffer has to be set first\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
if (!fh->overlay_settings.format) {
dprintk(1,
KERN_ERR
- "%s: setup_window() - no overlay format set\n",
- ZR_DEVNAME(zr));
+ "%s: %s - no overlay format set\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
@@ -1241,8 +1184,8 @@ setup_window (struct file *file,
width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
dprintk(1,
KERN_ERR
- "%s: setup_window() - width = %d or height = %d invalid\n",
- ZR_DEVNAME(zr), width, height);
+ "%s: %s - width = %d or height = %d invalid\n",
+ ZR_DEVNAME(zr), __func__, width, height);
return -EINVAL;
}
@@ -1284,8 +1227,8 @@ setup_window (struct file *file,
if (vcp == NULL) {
dprintk(1,
KERN_ERR
- "%s: setup_window() - Alloc of clip mask failed\n",
- ZR_DEVNAME(zr));
+ "%s: %s - Alloc of clip mask failed\n",
+ ZR_DEVNAME(zr), __func__);
return -ENOMEM;
}
if (copy_from_user
@@ -1293,7 +1236,7 @@ setup_window (struct file *file,
vfree(vcp);
return -EFAULT;
}
- write_overlay_mask(file, vcp, clipcount);
+ write_overlay_mask(fh, vcp, clipcount);
vfree(vcp);
}
@@ -1309,11 +1252,8 @@ setup_window (struct file *file,
return wait_grab_pending(zr);
}
-static int
-setup_overlay (struct file *file,
- int on)
+static int setup_overlay(struct zoran_fh *fh, int on)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
/* If there is nothing to do, return immediatly */
@@ -1326,16 +1266,16 @@ setup_overlay (struct file *file,
fh->overlay_active == ZORAN_FREE) {
dprintk(1,
KERN_ERR
- "%s: setup_overlay() - overlay is already active for another session\n",
- ZR_DEVNAME(zr));
+ "%s: %s - overlay is already active for another session\n",
+ ZR_DEVNAME(zr), __func__);
return -EBUSY;
}
if (!on && zr->overlay_active != ZORAN_FREE &&
fh->overlay_active == ZORAN_FREE) {
dprintk(1,
KERN_ERR
- "%s: setup_overlay() - you cannot cancel someone else's session\n",
- ZR_DEVNAME(zr));
+ "%s: %s - you cannot cancel someone else's session\n",
+ ZR_DEVNAME(zr), __func__);
return -EPERM;
}
@@ -1351,15 +1291,15 @@ setup_overlay (struct file *file,
if (!zr->vbuf_base || !fh->overlay_settings.is_set) {
dprintk(1,
KERN_ERR
- "%s: setup_overlay() - buffer or window not set\n",
- ZR_DEVNAME(zr));
+ "%s: %s - buffer or window not set\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
if (!fh->overlay_settings.format) {
dprintk(1,
KERN_ERR
- "%s: setup_overlay() - no overlay format set\n",
- ZR_DEVNAME(zr));
+ "%s: %s - no overlay format set\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
zr->overlay_active = fh->overlay_active = ZORAN_LOCKED;
@@ -1376,41 +1316,54 @@ setup_overlay (struct file *file,
return wait_grab_pending(zr);
}
- /* get the status of a buffer in the clients buffer queue */
-static int
-zoran_v4l2_buffer_status (struct file *file,
- struct v4l2_buffer *buf,
- int num)
+/* get the status of a buffer in the clients buffer queue */
+static int zoran_v4l2_buffer_status(struct zoran_fh *fh,
+ struct v4l2_buffer *buf, int num)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
+ unsigned long flags;
buf->flags = V4L2_BUF_FLAG_MAPPED;
switch (fh->map_mode) {
case ZORAN_MAP_MODE_RAW:
-
/* check range */
- if (num < 0 || num >= fh->v4l_buffers.num_buffers ||
- !fh->v4l_buffers.allocated) {
+ if (num < 0 || num >= fh->buffers.num_buffers ||
+ !fh->buffers.allocated) {
dprintk(1,
KERN_ERR
- "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
- ZR_DEVNAME(zr));
+ "%s: %s - wrong number or buffers not allocated\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
+ spin_lock_irqsave(&zr->spinlock, flags);
+ dprintk(3,
+ KERN_DEBUG
+ "%s: %s() - raw active=%c, buffer %d: state=%c, map=%c\n",
+ ZR_DEVNAME(zr), __func__,
+ "FAL"[fh->buffers.active], num,
+ "UPMD"[zr->v4l_buffers.buffer[num].state],
+ fh->buffers.buffer[num].map ? 'Y' : 'N');
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+#if 0
+ /* Process is the one capturing? */
+ if (fh->v4l_buffers.active != ZORAN_FREE &&
+ /* Buffer ready to DQBUF? */
+ zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
+ res = POLLIN | POLLRDNORM;
+#endif
+
buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->length = fh->v4l_buffers.buffer_size;
+ buf->length = fh->buffers.buffer_size;
/* get buffer */
- buf->bytesused = fh->v4l_buffers.buffer[num].bs.length;
- if (fh->v4l_buffers.buffer[num].state == BUZ_STATE_DONE ||
- fh->v4l_buffers.buffer[num].state == BUZ_STATE_USER) {
- buf->sequence = fh->v4l_buffers.buffer[num].bs.seq;
+ buf->bytesused = fh->buffers.buffer[num].bs.length;
+ if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
+ fh->buffers.buffer[num].state == BUZ_STATE_USER) {
+ buf->sequence = fh->buffers.buffer[num].bs.seq;
buf->flags |= V4L2_BUF_FLAG_DONE;
- buf->timestamp =
- fh->v4l_buffers.buffer[num].bs.timestamp;
+ buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
} else {
buf->flags |= V4L2_BUF_FLAG_QUEUED;
}
@@ -1426,28 +1379,26 @@ zoran_v4l2_buffer_status (struct file *file,
case ZORAN_MAP_MODE_JPG_PLAY:
/* check range */
- if (num < 0 || num >= fh->jpg_buffers.num_buffers ||
- !fh->jpg_buffers.allocated) {
+ if (num < 0 || num >= fh->buffers.num_buffers ||
+ !fh->buffers.allocated) {
dprintk(1,
KERN_ERR
- "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
- ZR_DEVNAME(zr));
+ "%s: %s - wrong number or buffers not allocated\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
V4L2_BUF_TYPE_VIDEO_CAPTURE :
V4L2_BUF_TYPE_VIDEO_OUTPUT;
- buf->length = fh->jpg_buffers.buffer_size;
+ buf->length = fh->buffers.buffer_size;
/* these variables are only written after frame has been captured */
- if (fh->jpg_buffers.buffer[num].state == BUZ_STATE_DONE ||
- fh->jpg_buffers.buffer[num].state == BUZ_STATE_USER) {
- buf->sequence = fh->jpg_buffers.buffer[num].bs.seq;
- buf->timestamp =
- fh->jpg_buffers.buffer[num].bs.timestamp;
- buf->bytesused =
- fh->jpg_buffers.buffer[num].bs.length;
+ if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
+ fh->buffers.buffer[num].state == BUZ_STATE_USER) {
+ buf->sequence = fh->buffers.buffer[num].bs.seq;
+ buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
+ buf->bytesused = fh->buffers.buffer[num].bs.length;
buf->flags |= V4L2_BUF_FLAG_DONE;
} else {
buf->flags |= V4L2_BUF_FLAG_QUEUED;
@@ -1455,14 +1406,11 @@ zoran_v4l2_buffer_status (struct file *file,
/* which fields are these? */
if (fh->jpg_settings.TmpDcm != 1)
- buf->field =
- fh->jpg_settings.
- odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+ buf->field = fh->jpg_settings.odd_even ?
+ V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
else
- buf->field =
- fh->jpg_settings.
- odd_even ? V4L2_FIELD_SEQ_TB :
- V4L2_FIELD_SEQ_BT;
+ buf->field = fh->jpg_settings.odd_even ?
+ V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT;
break;
@@ -1470,8 +1418,8 @@ zoran_v4l2_buffer_status (struct file *file,
dprintk(5,
KERN_ERR
- "%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n",
- ZR_DEVNAME(zr), buf->type, fh->map_mode);
+ "%s: %s - invalid buffer type|map_mode (%d|%d)\n",
+ ZR_DEVNAME(zr), __func__, buf->type, fh->map_mode);
return -EINVAL;
}
@@ -1492,31 +1440,15 @@ zoran_set_norm (struct zoran *zr,
zr->jpg_buffers.active != ZORAN_FREE) {
dprintk(1,
KERN_WARNING
- "%s: set_norm() called while in playback/capture mode\n",
- ZR_DEVNAME(zr));
+ "%s: %s called while in playback/capture mode\n",
+ ZR_DEVNAME(zr), __func__);
return -EBUSY;
}
- if (lock_norm && norm != zr->norm) {
- if (lock_norm > 1) {
- dprintk(1,
- KERN_WARNING
- "%s: set_norm() - TV standard is locked, can not switch norm\n",
- ZR_DEVNAME(zr));
- return -EPERM;
- } else {
- dprintk(1,
- KERN_WARNING
- "%s: set_norm() - TV standard is locked, norm was not changed\n",
- ZR_DEVNAME(zr));
- norm = zr->norm;
- }
- }
-
if (!(norm & zr->card.norms)) {
dprintk(1,
- KERN_ERR "%s: set_norm() - unsupported norm %llx\n",
- ZR_DEVNAME(zr), norm);
+ KERN_ERR "%s: %s - unsupported norm %llx\n",
+ ZR_DEVNAME(zr), __func__, norm);
return -EINVAL;
}
@@ -1525,7 +1457,7 @@ zoran_set_norm (struct zoran *zr,
v4l2_std_id std = 0;
decoder_call(zr, video, querystd, &std);
- decoder_s_std(zr, std);
+ decoder_call(zr, tuner, s_std, std);
/* let changes come into effect */
ssleep(2);
@@ -1534,10 +1466,10 @@ zoran_set_norm (struct zoran *zr,
if (status & V4L2_IN_ST_NO_SIGNAL) {
dprintk(1,
KERN_ERR
- "%s: set_norm() - no norm detected\n",
- ZR_DEVNAME(zr));
+ "%s: %s - no norm detected\n",
+ ZR_DEVNAME(zr), __func__);
/* reset norm */
- decoder_s_std(zr, zr->norm);
+ decoder_call(zr, tuner, s_std, zr->norm);
return -EIO;
}
@@ -1556,7 +1488,7 @@ zoran_set_norm (struct zoran *zr,
if (on)
zr36057_overlay(zr, 0);
- decoder_s_std(zr, norm);
+ decoder_call(zr, tuner, s_std, norm);
encoder_call(zr, video, s_std_output, norm);
if (on)
@@ -1582,23 +1514,23 @@ zoran_set_input (struct zoran *zr,
zr->jpg_buffers.active != ZORAN_FREE) {
dprintk(1,
KERN_WARNING
- "%s: set_input() called while in playback/capture mode\n",
- ZR_DEVNAME(zr));
+ "%s: %s called while in playback/capture mode\n",
+ ZR_DEVNAME(zr), __func__);
return -EBUSY;
}
if (input < 0 || input >= zr->card.inputs) {
dprintk(1,
KERN_ERR
- "%s: set_input() - unnsupported input %d\n",
- ZR_DEVNAME(zr), input);
+ "%s: %s - unnsupported input %d\n",
+ ZR_DEVNAME(zr), __func__, input);
return -EINVAL;
}
route.input = zr->card.input[input].muxsel;
zr->input = input;
- decoder_s_routing(zr, &route);
+ decoder_call(zr, video, s_routing, &route);
return 0;
}
@@ -1745,7 +1677,7 @@ sparams_unlock_and_return:
mutex_lock(&zr->resource_lock);
- if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+ if (fh->buffers.allocated) {
dprintk(1,
KERN_ERR
"%s: BUZIOC_REQBUFS - buffers already allocated\n",
@@ -1754,17 +1686,17 @@ sparams_unlock_and_return:
goto jpgreqbuf_unlock_and_return;
}
- fh->jpg_buffers.num_buffers = breq->count;
- fh->jpg_buffers.buffer_size = breq->size;
+ /* The next mmap will map the MJPEG buffers - could
+ * also be *_PLAY, but it doesn't matter here */
+ map_mode_jpg(fh, 0);
+ fh->buffers.num_buffers = breq->count;
+ fh->buffers.buffer_size = breq->size;
- if (jpg_fbuffer_alloc(file)) {
+ if (jpg_fbuffer_alloc(fh)) {
res = -ENOMEM;
goto jpgreqbuf_unlock_and_return;
}
- /* The next mmap will map the MJPEG buffers - could
- * also be *_PLAY, but it doesn't matter here */
- fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
jpgreqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock);
@@ -1779,7 +1711,7 @@ jpgreqbuf_unlock_and_return:
ZR_DEVNAME(zr), *frame);
mutex_lock(&zr->resource_lock);
- res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
+ res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_COMPRESS);
mutex_unlock(&zr->resource_lock);
return res;
@@ -1793,7 +1725,7 @@ jpgreqbuf_unlock_and_return:
ZR_DEVNAME(zr), *frame);
mutex_lock(&zr->resource_lock);
- res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
+ res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_DECOMPRESS);
mutex_unlock(&zr->resource_lock);
return res;
@@ -1807,7 +1739,15 @@ jpgreqbuf_unlock_and_return:
dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
mutex_lock(&zr->resource_lock);
- res = jpg_sync(file, bsync);
+
+ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+ dprintk(2, KERN_WARNING
+ "%s: %s - not in jpg capture mode\n",
+ ZR_DEVNAME(zr), __func__);
+ res = -EINVAL;
+ } else {
+ res = jpg_sync(fh, bsync);
+ }
mutex_unlock(&zr->resource_lock);
return res;
@@ -1843,7 +1783,7 @@ jpgreqbuf_unlock_and_return:
goto gstat_unlock_and_return;
}
- decoder_s_routing(zr, &route);
+ decoder_call(zr, video, s_routing, &route);
/* sleep 1 second */
ssleep(1);
@@ -1854,7 +1794,7 @@ jpgreqbuf_unlock_and_return:
/* restore previous input and norm */
route.input = zr->card.input[zr->input].muxsel;
- decoder_s_routing(zr, &route);
+ decoder_call(zr, video, s_routing, &route);
gstat_unlock_and_return:
mutex_unlock(&zr->resource_lock);
@@ -1886,18 +1826,10 @@ static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *v
struct zoran *zr = fh->zr;
int i, res = 0;
- vmbuf->size =
- fh->v4l_buffers.num_buffers *
- fh->v4l_buffers.buffer_size;
- vmbuf->frames = fh->v4l_buffers.num_buffers;
- for (i = 0; i < vmbuf->frames; i++) {
- vmbuf->offsets[i] =
- i * fh->v4l_buffers.buffer_size;
- }
mutex_lock(&zr->resource_lock);
- if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+ if (fh->buffers.allocated) {
dprintk(1,
KERN_ERR
"%s: VIDIOCGMBUF - buffers already allocated\n",
@@ -1906,13 +1838,19 @@ static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *v
goto v4l1reqbuf_unlock_and_return;
}
- if (v4l_fbuffer_alloc(file)) {
+ /* The next mmap will map the V4L buffers */
+ map_mode_raw(fh);
+
+ if (v4l_fbuffer_alloc(fh)) {
res = -ENOMEM;
goto v4l1reqbuf_unlock_and_return;
}
- /* The next mmap will map the V4L buffers */
- fh->map_mode = ZORAN_MAP_MODE_RAW;
+ vmbuf->size = fh->buffers.num_buffers * fh->buffers.buffer_size;
+ vmbuf->frames = fh->buffers.num_buffers;
+ for (i = 0; i < vmbuf->frames; i++)
+ vmbuf->offsets[i] = i * fh->buffers.buffer_size;
+
v4l1reqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock);
@@ -2195,14 +2133,10 @@ static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh,
fmt->fmt.win.clipcount,
fmt->fmt.win.bitmap);
mutex_lock(&zr->resource_lock);
- res = setup_window(file, fmt->fmt.win.w.left,
- fmt->fmt.win.w.top,
- fmt->fmt.win.w.width,
- fmt->fmt.win.w.height,
- (struct v4l2_clip __user *)
- fmt->fmt.win.clips,
- fmt->fmt.win.clipcount,
- fmt->fmt.win.bitmap);
+ res = setup_window(fh, fmt->fmt.win.w.left, fmt->fmt.win.w.top,
+ fmt->fmt.win.w.width, fmt->fmt.win.w.height,
+ (struct v4l2_clip __user *)fmt->fmt.win.clips,
+ fmt->fmt.win.clipcount, fmt->fmt.win.bitmap);
mutex_unlock(&zr->resource_lock);
return res;
}
@@ -2225,15 +2159,15 @@ static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
mutex_lock(&zr->resource_lock);
- settings = fh->jpg_settings;
-
- if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
+ if (fh->buffers.allocated) {
dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
- ZR_DEVNAME(zr));
+ ZR_DEVNAME(zr));
res = -EBUSY;
goto sfmtjpg_unlock_and_return;
}
+ settings = fh->jpg_settings;
+
/* we actually need to set 'real' parameters now */
if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT)
settings.TmpDcm = 1;
@@ -2271,6 +2205,9 @@ static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
/* it's ok, so set them */
fh->jpg_settings = settings;
+ map_mode_jpg(fh, fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
/* tell the user what we actually did */
fmt->fmt.pix.width = settings.img_width / settings.HorDcm;
fmt->fmt.pix.height = settings.img_height * 2 /
@@ -2281,15 +2218,10 @@ static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
else
fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
- fh->jpg_buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
fmt->fmt.pix.bytesperline = 0;
- fmt->fmt.pix.sizeimage = fh->jpg_buffers.buffer_size;
+ fmt->fmt.pix.sizeimage = fh->buffers.buffer_size;
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- /* we hereby abuse this variable to show that
- * we're gonna do mjpeg capture */
- fh->map_mode = (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
- ZORAN_MAP_MODE_JPG_REC : ZORAN_MAP_MODE_JPG_PLAY;
sfmtjpg_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
@@ -2314,9 +2246,11 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat);
return -EINVAL;
}
+
mutex_lock(&zr->resource_lock);
- if (fh->jpg_buffers.allocated ||
- (fh->v4l_buffers.allocated && fh->v4l_buffers.active != ZORAN_FREE)) {
+
+ if ((fh->map_mode != ZORAN_MAP_MODE_RAW && fh->buffers.allocated) ||
+ fh->buffers.active != ZORAN_FREE) {
dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
ZR_DEVNAME(zr));
res = -EBUSY;
@@ -2327,13 +2261,14 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
fmt->fmt.pix.width = BUZ_MAX_WIDTH;
- res = zoran_v4l_set_format(file, fmt->fmt.pix.width,
- fmt->fmt.pix.height, &zoran_formats[i]);
+ map_mode_raw(fh);
+
+ res = zoran_v4l_set_format(fh, fmt->fmt.pix.width, fmt->fmt.pix.height,
+ &zoran_formats[i]);
if (res)
goto sfmtv4l_unlock_and_return;
- /* tell the user the
- * results/missing stuff */
+ /* tell the user the results/missing stuff */
fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline;
fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
@@ -2342,7 +2277,6 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
else
fmt->fmt.pix.field = V4L2_FIELD_TOP;
- fh->map_mode = ZORAN_MAP_MODE_RAW;
sfmtv4l_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
@@ -2390,9 +2324,8 @@ static int zoran_s_fbuf(struct file *file, void *__fh,
}
mutex_lock(&zr->resource_lock);
- res = setup_fbuffer(file, fb->base, &zoran_formats[i],
- fb->fmt.width, fb->fmt.height,
- fb->fmt.bytesperline);
+ res = setup_fbuffer(fh, fb->base, &zoran_formats[i], fb->fmt.width,
+ fb->fmt.height, fb->fmt.bytesperline);
mutex_unlock(&zr->resource_lock);
return res;
@@ -2405,7 +2338,7 @@ static int zoran_overlay(struct file *file, void *__fh, unsigned int on)
int res;
mutex_lock(&zr->resource_lock);
- res = setup_overlay(file, on);
+ res = setup_overlay(fh, on);
mutex_unlock(&zr->resource_lock);
return res;
@@ -2431,7 +2364,7 @@ static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffe
return zoran_streamoff(file, fh, req->type);
mutex_lock(&zr->resource_lock);
- if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
+ if (fh->buffers.allocated) {
dprintk(2,
KERN_ERR
"%s: VIDIOC_REQBUFS - buffers already allocated\n",
@@ -2441,46 +2374,38 @@ static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffe
}
if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
- req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-
+ req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
/* control user input */
if (req->count < 2)
req->count = 2;
if (req->count > v4l_nbufs)
req->count = v4l_nbufs;
- fh->v4l_buffers.num_buffers = req->count;
- if (v4l_fbuffer_alloc(file)) {
+ /* The next mmap will map the V4L buffers */
+ map_mode_raw(fh);
+ fh->buffers.num_buffers = req->count;
+
+ if (v4l_fbuffer_alloc(fh)) {
res = -ENOMEM;
goto v4l2reqbuf_unlock_and_return;
}
-
- /* The next mmap will map the V4L buffers */
- fh->map_mode = ZORAN_MAP_MODE_RAW;
-
} else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
- fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
-
+ fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
/* we need to calculate size ourselves now */
if (req->count < 4)
req->count = 4;
if (req->count > jpg_nbufs)
req->count = jpg_nbufs;
- fh->jpg_buffers.num_buffers = req->count;
- fh->jpg_buffers.buffer_size =
- zoran_v4l2_calc_bufsize(&fh->jpg_settings);
- if (jpg_fbuffer_alloc(file)) {
+ /* The next mmap will map the MJPEG buffers */
+ map_mode_jpg(fh, req->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ fh->buffers.num_buffers = req->count;
+ fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
+ if (jpg_fbuffer_alloc(fh)) {
res = -ENOMEM;
goto v4l2reqbuf_unlock_and_return;
}
-
- /* The next mmap will map the MJPEG buffers */
- if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
- else
- fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY;
-
} else {
dprintk(1,
KERN_ERR
@@ -2499,15 +2424,10 @@ static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
- __u32 type = buf->type;
- int index = buf->index, res;
-
- memset(buf, 0, sizeof(*buf));
- buf->type = type;
- buf->index = index;
+ int res;
mutex_lock(&zr->resource_lock);
- res = zoran_v4l2_buffer_status(file, buf, buf->index);
+ res = zoran_v4l2_buffer_status(fh, buf, buf->index);
mutex_unlock(&zr->resource_lock);
return res;
@@ -2531,11 +2451,10 @@ static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
goto qbuf_unlock_and_return;
}
- res = zoran_v4l_queue_frame(file, buf->index);
+ res = zoran_v4l_queue_frame(fh, buf->index);
if (res)
goto qbuf_unlock_and_return;
- if (!zr->v4l_memgrab_active &&
- fh->v4l_buffers.active == ZORAN_LOCKED)
+ if (!zr->v4l_memgrab_active && fh->buffers.active == ZORAN_LOCKED)
zr36057_set_memgrab(zr, 1);
break;
@@ -2557,14 +2476,13 @@ static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
goto qbuf_unlock_and_return;
}
- res = zoran_jpg_queue_frame(file, buf->index,
- codec_mode);
+ res = zoran_jpg_queue_frame(fh, buf->index, codec_mode);
if (res != 0)
goto qbuf_unlock_and_return;
if (zr->codec_mode == BUZ_MODE_IDLE &&
- fh->jpg_buffers.active == ZORAN_LOCKED) {
+ fh->buffers.active == ZORAN_LOCKED)
zr36057_enable_jpg(zr, codec_mode);
- }
+
break;
default:
@@ -2604,11 +2522,11 @@ static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
res = -EAGAIN;
goto dqbuf_unlock_and_return;
}
- res = v4l_sync(file, num);
+ res = v4l_sync(fh, num);
if (res)
goto dqbuf_unlock_and_return;
zr->v4l_sync_tail++;
- res = zoran_v4l2_buffer_status(file, buf, num);
+ res = zoran_v4l2_buffer_status(fh, buf, num);
break;
case ZORAN_MAP_MODE_JPG_REC:
@@ -2636,10 +2554,10 @@ static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
res = -EAGAIN;
goto dqbuf_unlock_and_return;
}
- res = jpg_sync(file, &bs);
+ res = jpg_sync(fh, &bs);
if (res)
goto dqbuf_unlock_and_return;
- res = zoran_v4l2_buffer_status(file, buf, bs.frame);
+ res = zoran_v4l2_buffer_status(fh, buf, bs.frame);
break;
}
@@ -2667,12 +2585,12 @@ static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type
switch (fh->map_mode) {
case ZORAN_MAP_MODE_RAW: /* raw capture */
if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
- fh->v4l_buffers.active != ZORAN_ACTIVE) {
+ fh->buffers.active != ZORAN_ACTIVE) {
res = -EBUSY;
goto strmon_unlock_and_return;
}
- zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_LOCKED;
+ zr->v4l_buffers.active = fh->buffers.active = ZORAN_LOCKED;
zr->v4l_settings = fh->v4l_settings;
zr->v4l_sync_tail = zr->v4l_pend_tail;
@@ -2686,12 +2604,12 @@ static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type
case ZORAN_MAP_MODE_JPG_PLAY:
/* what is the codec mode right now? */
if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
- fh->jpg_buffers.active != ZORAN_ACTIVE) {
+ fh->buffers.active != ZORAN_ACTIVE) {
res = -EBUSY;
goto strmon_unlock_and_return;
}
- zr->jpg_buffers.active = fh->jpg_buffers.active = ZORAN_LOCKED;
+ zr->jpg_buffers.active = fh->buffers.active = ZORAN_LOCKED;
if (zr->jpg_que_head != zr->jpg_que_tail) {
/* Start the jpeg codec when the first frame is queued */
@@ -2718,12 +2636,13 @@ static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type typ
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int i, res = 0;
+ unsigned long flags;
mutex_lock(&zr->resource_lock);
switch (fh->map_mode) {
case ZORAN_MAP_MODE_RAW: /* raw capture */
- if (fh->v4l_buffers.active == ZORAN_FREE &&
+ if (fh->buffers.active == ZORAN_FREE &&
zr->v4l_buffers.active != ZORAN_FREE) {
res = -EPERM; /* stay off other's settings! */
goto strmoff_unlock_and_return;
@@ -2731,30 +2650,30 @@ static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type typ
if (zr->v4l_buffers.active == ZORAN_FREE)
goto strmoff_unlock_and_return;
+ spin_lock_irqsave(&zr->spinlock, flags);
/* unload capture */
if (zr->v4l_memgrab_active) {
- unsigned long flags;
- spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
- spin_unlock_irqrestore(&zr->spinlock, flags);
}
- for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
+ for (i = 0; i < fh->buffers.num_buffers; i++)
zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;
- fh->v4l_buffers = zr->v4l_buffers;
+ fh->buffers = zr->v4l_buffers;
- zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_FREE;
+ zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
zr->v4l_grab_seq = 0;
zr->v4l_pend_head = zr->v4l_pend_tail = 0;
zr->v4l_sync_tail = 0;
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+
break;
case ZORAN_MAP_MODE_JPG_REC:
case ZORAN_MAP_MODE_JPG_PLAY:
- if (fh->jpg_buffers.active == ZORAN_FREE &&
+ if (fh->buffers.active == ZORAN_FREE &&
zr->jpg_buffers.active != ZORAN_FREE) {
res = -EPERM; /* stay off other's settings! */
goto strmoff_unlock_and_return;
@@ -2762,7 +2681,7 @@ static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type typ
if (zr->jpg_buffers.active == ZORAN_FREE)
goto strmoff_unlock_and_return;
- res = jpg_qbuf(file, -1,
+ res = jpg_qbuf(fh, -1,
(fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
BUZ_MODE_MOTION_COMPRESS :
BUZ_MODE_MOTION_DECOMPRESS);
@@ -3023,7 +2942,7 @@ static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
mutex_lock(&zr->resource_lock);
- if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
+ if (fh->buffers.allocated) {
dprintk(1, KERN_ERR
"%s: VIDIOC_S_CROP - cannot change settings while active\n",
ZR_DEVNAME(zr));
@@ -3101,8 +3020,7 @@ static int zoran_s_jpegcomp(struct file *file, void *__fh,
mutex_lock(&zr->resource_lock);
- if (fh->v4l_buffers.active != ZORAN_FREE ||
- fh->jpg_buffers.active != ZORAN_FREE) {
+ if (fh->buffers.active != ZORAN_FREE) {
dprintk(1, KERN_WARNING
"%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
ZR_DEVNAME(zr));
@@ -3113,9 +3031,9 @@ static int zoran_s_jpegcomp(struct file *file, void *__fh,
res = zoran_check_jpg_settings(zr, &settings, 0);
if (res)
goto sjpegc_unlock_and_return;
- if (!fh->jpg_buffers.allocated)
- fh->jpg_buffers.buffer_size =
- zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+ if (!fh->buffers.allocated)
+ fh->buffers.buffer_size =
+ zoran_v4l2_calc_bufsize(&fh->jpg_settings);
fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
sjpegc_unlock_and_return:
mutex_unlock(&zr->resource_lock);
@@ -3152,11 +3070,11 @@ zoran_poll (struct file *file,
KERN_DEBUG
"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
ZR_DEVNAME(zr), __func__,
- "FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
+ "FAL"[fh->buffers.active], zr->v4l_sync_tail,
"UPMD"[zr->v4l_buffers.buffer[frame].state],
zr->v4l_pend_tail, zr->v4l_pend_head);
/* Process is the one capturing? */
- if (fh->v4l_buffers.active != ZORAN_FREE &&
+ if (fh->buffers.active != ZORAN_FREE &&
/* Buffer ready to DQBUF? */
zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
res = POLLIN | POLLRDNORM;
@@ -3174,10 +3092,10 @@ zoran_poll (struct file *file,
KERN_DEBUG
"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
ZR_DEVNAME(zr), __func__,
- "FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
+ "FAL"[fh->buffers.active], zr->jpg_que_tail,
"UPMD"[zr->jpg_buffers.buffer[frame].state],
zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
- if (fh->jpg_buffers.active != ZORAN_FREE &&
+ if (fh->buffers.active != ZORAN_FREE &&
zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
res = POLLIN | POLLRDNORM;
@@ -3191,8 +3109,8 @@ zoran_poll (struct file *file,
default:
dprintk(1,
KERN_ERR
- "%s: zoran_poll() - internal error, unknown map_mode=%d\n",
- ZR_DEVNAME(zr), fh->map_mode);
+ "%s: %s - internal error, unknown map_mode=%d\n",
+ ZR_DEVNAME(zr), __func__, fh->map_mode);
res = POLLNVAL;
}
@@ -3226,92 +3144,53 @@ static void
zoran_vm_close (struct vm_area_struct *vma)
{
struct zoran_mapping *map = vma->vm_private_data;
- struct file *file = map->file;
- struct zoran_fh *fh = file->private_data;
+ struct zoran_fh *fh = map->file->private_data;
struct zoran *zr = fh->zr;
int i;
- map->count--;
- if (map->count == 0) {
- switch (fh->map_mode) {
- case ZORAN_MAP_MODE_JPG_REC:
- case ZORAN_MAP_MODE_JPG_PLAY:
-
- dprintk(3, KERN_INFO "%s: munmap(MJPEG)\n",
- ZR_DEVNAME(zr));
-
- for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
- if (fh->jpg_buffers.buffer[i].map == map) {
- fh->jpg_buffers.buffer[i].map =
- NULL;
- }
- }
- kfree(map);
-
- for (i = 0; i < fh->jpg_buffers.num_buffers; i++)
- if (fh->jpg_buffers.buffer[i].map)
- break;
- if (i == fh->jpg_buffers.num_buffers) {
- mutex_lock(&zr->resource_lock);
-
- if (fh->jpg_buffers.active != ZORAN_FREE) {
- jpg_qbuf(file, -1, zr->codec_mode);
- zr->jpg_buffers.allocated = 0;
- zr->jpg_buffers.active =
- fh->jpg_buffers.active =
- ZORAN_FREE;
- }
- jpg_fbuffer_free(file);
- mutex_unlock(&zr->resource_lock);
- }
-
- break;
+ if (--map->count > 0)
+ return;
- case ZORAN_MAP_MODE_RAW:
+ dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr),
+ __func__, mode_name(fh->map_mode));
- dprintk(3, KERN_INFO "%s: munmap(V4L)\n",
- ZR_DEVNAME(zr));
+ for (i = 0; i < fh->buffers.num_buffers; i++) {
+ if (fh->buffers.buffer[i].map == map)
+ fh->buffers.buffer[i].map = NULL;
+ }
+ kfree(map);
- for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
- if (fh->v4l_buffers.buffer[i].map == map) {
- /* unqueue/unmap */
- fh->v4l_buffers.buffer[i].map =
- NULL;
- }
- }
- kfree(map);
+ /* Any buffers still mapped? */
+ for (i = 0; i < fh->buffers.num_buffers; i++)
+ if (fh->buffers.buffer[i].map)
+ return;
- for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
- if (fh->v4l_buffers.buffer[i].map)
- break;
- if (i == fh->v4l_buffers.num_buffers) {
- mutex_lock(&zr->resource_lock);
-
- if (fh->v4l_buffers.active != ZORAN_FREE) {
- unsigned long flags;
-
- spin_lock_irqsave(&zr->spinlock, flags);
- zr36057_set_memgrab(zr, 0);
- zr->v4l_buffers.allocated = 0;
- zr->v4l_buffers.active =
- fh->v4l_buffers.active =
- ZORAN_FREE;
- spin_unlock_irqrestore(&zr->spinlock, flags);
- }
- v4l_fbuffer_free(file);
- mutex_unlock(&zr->resource_lock);
- }
+ dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr),
+ __func__, mode_name(fh->map_mode));
- break;
+ mutex_lock(&zr->resource_lock);
- default:
- printk(KERN_ERR
- "%s: munmap() - internal error - unknown map mode %d\n",
- ZR_DEVNAME(zr), fh->map_mode);
- break;
+ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+ if (fh->buffers.active != ZORAN_FREE) {
+ unsigned long flags;
+ spin_lock_irqsave(&zr->spinlock, flags);
+ zr36057_set_memgrab(zr, 0);
+ zr->v4l_buffers.allocated = 0;
+ zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+ }
+ v4l_fbuffer_free(fh);
+ } else {
+ if (fh->buffers.active != ZORAN_FREE) {
+ jpg_qbuf(fh, -1, zr->codec_mode);
+ zr->jpg_buffers.allocated = 0;
+ zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
}
+ jpg_fbuffer_free(fh);
}
+
+ mutex_unlock(&zr->resource_lock);
}
static struct vm_operations_struct zoran_vm_ops = {
@@ -3334,90 +3213,106 @@ zoran_mmap (struct file *file,
int res = 0;
dprintk(3,
- KERN_INFO "%s: mmap(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
- ZR_DEVNAME(zr),
- fh->map_mode == ZORAN_MAP_MODE_RAW ? "V4L" : "MJPEG",
- vma->vm_start, vma->vm_end, size);
+ KERN_INFO "%s: %s(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
+ ZR_DEVNAME(zr), __func__,
+ mode_name(fh->map_mode), vma->vm_start, vma->vm_end, size);
if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) ||
!(vma->vm_flags & VM_WRITE)) {
dprintk(1,
KERN_ERR
- "%s: mmap() - no MAP_SHARED/PROT_{READ,WRITE} given\n",
- ZR_DEVNAME(zr));
+ "%s: %s - no MAP_SHARED/PROT_{READ,WRITE} given\n",
+ ZR_DEVNAME(zr), __func__);
return -EINVAL;
}
- switch (fh->map_mode) {
+ mutex_lock(&zr->resource_lock);
- case ZORAN_MAP_MODE_JPG_REC:
- case ZORAN_MAP_MODE_JPG_PLAY:
+ if (!fh->buffers.allocated) {
+ dprintk(1,
+ KERN_ERR
+ "%s: %s(%s) - buffers not yet allocated\n",
+ ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode));
+ res = -ENOMEM;
+ goto mmap_unlock_and_return;
+ }
- /* lock */
- mutex_lock(&zr->resource_lock);
+ first = offset / fh->buffers.buffer_size;
+ last = first - 1 + size / fh->buffers.buffer_size;
+ if (offset % fh->buffers.buffer_size != 0 ||
+ size % fh->buffers.buffer_size != 0 || first < 0 ||
+ last < 0 || first >= fh->buffers.num_buffers ||
+ last >= fh->buffers.buffer_size) {
+ dprintk(1,
+ KERN_ERR
+ "%s: %s(%s) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
+ ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), offset, size,
+ fh->buffers.buffer_size,
+ fh->buffers.num_buffers);
+ res = -EINVAL;
+ goto mmap_unlock_and_return;
+ }
- /* Map the MJPEG buffers */
- if (!fh->jpg_buffers.allocated) {
+ /* Check if any buffers are already mapped */
+ for (i = first; i <= last; i++) {
+ if (fh->buffers.buffer[i].map) {
dprintk(1,
KERN_ERR
- "%s: zoran_mmap(MJPEG) - buffers not yet allocated\n",
- ZR_DEVNAME(zr));
- res = -ENOMEM;
- goto jpg_mmap_unlock_and_return;
+ "%s: %s(%s) - buffer %d already mapped\n",
+ ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), i);
+ res = -EBUSY;
+ goto mmap_unlock_and_return;
}
+ }
- first = offset / fh->jpg_buffers.buffer_size;
- last = first - 1 + size / fh->jpg_buffers.buffer_size;
- if (offset % fh->jpg_buffers.buffer_size != 0 ||
- size % fh->jpg_buffers.buffer_size != 0 || first < 0 ||
- last < 0 || first >= fh->jpg_buffers.num_buffers ||
- last >= fh->jpg_buffers.num_buffers) {
- dprintk(1,
- KERN_ERR
- "%s: mmap(MJPEG) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
- ZR_DEVNAME(zr), offset, size,
- fh->jpg_buffers.buffer_size,
- fh->jpg_buffers.num_buffers);
- res = -EINVAL;
- goto jpg_mmap_unlock_and_return;
- }
+ /* map these buffers */
+ map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
+ if (!map) {
+ res = -ENOMEM;
+ goto mmap_unlock_and_return;
+ }
+ map->file = file;
+ map->count = 1;
+
+ vma->vm_ops = &zoran_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_private_data = map;
+
+ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
for (i = first; i <= last; i++) {
- if (fh->jpg_buffers.buffer[i].map) {
+ todo = size;
+ if (todo > fh->buffers.buffer_size)
+ todo = fh->buffers.buffer_size;
+ page = fh->buffers.buffer[i].v4l.fbuffer_phys;
+ if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
+ todo, PAGE_SHARED)) {
dprintk(1,
KERN_ERR
- "%s: mmap(MJPEG) - buffer %d already mapped\n",
- ZR_DEVNAME(zr), i);
- res = -EBUSY;
- goto jpg_mmap_unlock_and_return;
+ "%s: %s(V4L) - remap_pfn_range failed\n",
+ ZR_DEVNAME(zr), __func__);
+ res = -EAGAIN;
+ goto mmap_unlock_and_return;
}
+ size -= todo;
+ start += todo;
+ fh->buffers.buffer[i].map = map;
+ if (size == 0)
+ break;
}
-
- /* map these buffers (v4l_buffers[i]) */
- map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
- if (!map) {
- res = -ENOMEM;
- goto jpg_mmap_unlock_and_return;
- }
- map->file = file;
- map->count = 1;
-
- vma->vm_ops = &zoran_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_private_data = map;
-
+ } else {
for (i = first; i <= last; i++) {
for (j = 0;
- j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
+ j < fh->buffers.buffer_size / PAGE_SIZE;
j++) {
fraglen =
- (le32_to_cpu(fh->jpg_buffers.buffer[i].
+ (le32_to_cpu(fh->buffers.buffer[i].jpg.
frag_tab[2 * j + 1]) & ~1) << 1;
todo = size;
if (todo > fraglen)
todo = fraglen;
pos =
- le32_to_cpu(fh->jpg_buffers.
- buffer[i].frag_tab[2 * j]);
+ le32_to_cpu(fh->buffers.
+ buffer[i].jpg.frag_tab[2 * j]);
/* should just be pos on i386 */
page = virt_to_phys(bus_to_virt(pos))
>> PAGE_SHIFT;
@@ -3425,115 +3320,29 @@ zoran_mmap (struct file *file,
todo, PAGE_SHARED)) {
dprintk(1,
KERN_ERR
- "%s: zoran_mmap(V4L) - remap_pfn_range failed\n",
- ZR_DEVNAME(zr));
+ "%s: %s(V4L) - remap_pfn_range failed\n",
+ ZR_DEVNAME(zr), __func__);
res = -EAGAIN;
- goto jpg_mmap_unlock_and_return;
+ goto mmap_unlock_and_return;
}
size -= todo;
start += todo;
if (size == 0)
break;
- if (le32_to_cpu(fh->jpg_buffers.buffer[i].
+ if (le32_to_cpu(fh->buffers.buffer[i].jpg.
frag_tab[2 * j + 1]) & 1)
break; /* was last fragment */
}
- fh->jpg_buffers.buffer[i].map = map;
+ fh->buffers.buffer[i].map = map;
if (size == 0)
break;
}
- jpg_mmap_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- break;
-
- case ZORAN_MAP_MODE_RAW:
-
- mutex_lock(&zr->resource_lock);
-
- /* Map the V4L buffers */
- if (!fh->v4l_buffers.allocated) {
- dprintk(1,
- KERN_ERR
- "%s: zoran_mmap(V4L) - buffers not yet allocated\n",
- ZR_DEVNAME(zr));
- res = -ENOMEM;
- goto v4l_mmap_unlock_and_return;
- }
-
- first = offset / fh->v4l_buffers.buffer_size;
- last = first - 1 + size / fh->v4l_buffers.buffer_size;
- if (offset % fh->v4l_buffers.buffer_size != 0 ||
- size % fh->v4l_buffers.buffer_size != 0 || first < 0 ||
- last < 0 || first >= fh->v4l_buffers.num_buffers ||
- last >= fh->v4l_buffers.buffer_size) {
- dprintk(1,
- KERN_ERR
- "%s: mmap(V4L) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
- ZR_DEVNAME(zr), offset, size,
- fh->v4l_buffers.buffer_size,
- fh->v4l_buffers.num_buffers);
- res = -EINVAL;
- goto v4l_mmap_unlock_and_return;
- }
- for (i = first; i <= last; i++) {
- if (fh->v4l_buffers.buffer[i].map) {
- dprintk(1,
- KERN_ERR
- "%s: mmap(V4L) - buffer %d already mapped\n",
- ZR_DEVNAME(zr), i);
- res = -EBUSY;
- goto v4l_mmap_unlock_and_return;
- }
- }
-
- /* map these buffers (v4l_buffers[i]) */
- map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
- if (!map) {
- res = -ENOMEM;
- goto v4l_mmap_unlock_and_return;
- }
- map->file = file;
- map->count = 1;
-
- vma->vm_ops = &zoran_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_private_data = map;
-
- for (i = first; i <= last; i++) {
- todo = size;
- if (todo > fh->v4l_buffers.buffer_size)
- todo = fh->v4l_buffers.buffer_size;
- page = fh->v4l_buffers.buffer[i].fbuffer_phys;
- if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
- todo, PAGE_SHARED)) {
- dprintk(1,
- KERN_ERR
- "%s: zoran_mmap(V4L)i - remap_pfn_range failed\n",
- ZR_DEVNAME(zr));
- res = -EAGAIN;
- goto v4l_mmap_unlock_and_return;
- }
- size -= todo;
- start += todo;
- fh->v4l_buffers.buffer[i].map = map;
- if (size == 0)
- break;
- }
- v4l_mmap_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- break;
-
- default:
- dprintk(1,
- KERN_ERR
- "%s: zoran_mmap() - internal error - unknown map mode %d\n",
- ZR_DEVNAME(zr), fh->map_mode);
- break;
}
+mmap_unlock_and_return:
+ mutex_unlock(&zr->resource_lock);
+
return 0;
}
diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c
index 698b7b9ba..2e4d8147b 100644
--- a/linux/drivers/media/video/zr364xx.c
+++ b/linux/drivers/media/video/zr364xx.c
@@ -427,7 +427,6 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- memset(cap, 0, sizeof(*cap));
strcpy(cap->driver, DRIVER_DESC);
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
return 0;
@@ -438,8 +437,6 @@ static int zr364xx_vidioc_enum_input(struct file *file, void *priv,
{
if (i->index != 0)
return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = 0;
strcpy(i->name, DRIVER_DESC " Camera");
i->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
@@ -531,11 +528,6 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
{
if (f->index > 0)
return -EINVAL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(f, 0, sizeof(*f));
- f->index = 0;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
strcpy(f->description, "JPEG");
f->pixelformat = V4L2_PIX_FMT_JPEG;
@@ -552,8 +544,6 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -ENODEV;
cam = video_get_drvdata(vdev);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
return -EINVAL;
if (f->fmt.pix.field != V4L2_FIELD_ANY &&
@@ -579,10 +569,6 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
return -ENODEV;
cam = video_get_drvdata(vdev);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
@@ -604,8 +590,6 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return -ENODEV;
cam = video_get_drvdata(vdev);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
return -EINVAL;
if (f->fmt.pix.field != V4L2_FIELD_ANY &&