summaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/Kconfig151
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/au0828/au0828-video.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c6
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-gpio.c2
-rw-r--r--drivers/media/video/cafe_ccic.c2
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c2
-rw-r--r--drivers/media/video/cx18/Kconfig4
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h2
-rw-r--r--drivers/media/video/cx18/cx18-cards.c18
-rw-r--r--drivers/media/video/cx18/cx18-cards.h2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c27
-rw-r--r--drivers/media/video/cx18/cx18-driver.h25
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c70
-rw-r--r--drivers/media/video/cx18/cx18-fileops.h2
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c146
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c58
-rw-r--r--drivers/media/video/cx18/cx18-streams.c187
-rw-r--r--drivers/media/video/cx18/cx18-vbi.c2
-rw-r--r--drivers/media/video/cx18/cx18-version.h2
-rw-r--r--drivers/media/video/cx18/cx23418.h6
-rw-r--r--drivers/media/video/cx231xx/cx231xx-avcore.c2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-cards.c67
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dvb.c1
-rw-r--r--drivers/media/video/cx231xx/cx231xx-vbi.c2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c2
-rw-r--r--drivers/media/video/cx231xx/cx231xx.h2
-rw-r--r--drivers/media/video/cx23885/Kconfig1
-rw-r--r--drivers/media/video/cx23885/cimax2.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c1
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c2
-rw-r--r--drivers/media/video/cx23885/cx23885.h2
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c10
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c41
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c2
-rw-r--r--drivers/media/video/cx88/cx88-input.c2
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c42
-rw-r--r--drivers/media/video/cx88/cx88-video.c7
-rw-r--r--drivers/media/video/cx88/cx88.h11
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c4
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c2
-rw-r--r--drivers/media/video/em28xx/Kconfig2
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c49
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c9
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c160
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c4
-rw-r--r--drivers/media/video/em28xx/em28xx.h3
-rw-r--r--drivers/media/video/fsl-viu.c56
-rw-r--r--drivers/media/video/gspca/Kconfig9
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/cpia1.c6
-rw-r--r--drivers/media/video/gspca/gl860/gl860-mi1320.c2
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c15
-rw-r--r--drivers/media/video/gspca/gspca.c8
-rw-r--r--drivers/media/video/gspca/gspca.h6
-rw-r--r--drivers/media/video/gspca/jeilinj.c581
-rw-r--r--drivers/media/video/gspca/kinect.c429
-rw-r--r--drivers/media/video/gspca/mars.c2
-rw-r--r--drivers/media/video/gspca/mr97310a.c2
-rw-r--r--drivers/media/video/gspca/ov519.c4
-rw-r--r--drivers/media/video/gspca/sonixb.c2
-rw-r--r--drivers/media/video/gspca/spca500.c4
-rw-r--r--drivers/media/video/gspca/spca508.c7
-rw-r--r--drivers/media/video/gspca/sq905.c2
-rw-r--r--drivers/media/video/gspca/stk014.c15
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c2
-rw-r--r--drivers/media/video/gspca/sunplus.c99
-rw-r--r--drivers/media/video/gspca/t613.c17
-rw-r--r--drivers/media/video/gspca/zc3xx.c47
-rw-r--r--drivers/media/video/hexium_gemini.c2
-rw-r--r--drivers/media/video/imx074.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c4
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c2
-rw-r--r--drivers/media/video/m52790.c2
-rw-r--r--drivers/media/video/msp3400-driver.c6
-rw-r--r--drivers/media/video/msp3400-kthreads.c2
-rw-r--r--drivers/media/video/mt9m111.c14
-rw-r--r--drivers/media/video/mt9v022.c2
-rw-r--r--drivers/media/video/mt9v032.c773
-rw-r--r--drivers/media/video/mx3_camera.c60
-rw-r--r--drivers/media/video/omap/omap_vout.c4
-rw-r--r--drivers/media/video/omap/omap_voutlib.c6
-rw-r--r--drivers/media/video/omap1_camera.c47
-rw-r--r--drivers/media/video/omap3isp/isp.c42
-rw-r--r--drivers/media/video/omap3isp/isp.h12
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c37
-rw-r--r--drivers/media/video/omap3isp/ispccdc.h4
-rw-r--r--drivers/media/video/omap3isp/ispccp2.c2
-rw-r--r--drivers/media/video/omap3isp/ispcsi2.c2
-rw-r--r--drivers/media/video/omap3isp/isppreview.c22
-rw-r--r--drivers/media/video/omap3isp/isppreview.h2
-rw-r--r--drivers/media/video/omap3isp/ispqueue.c6
-rw-r--r--drivers/media/video/omap3isp/ispqueue.h4
-rw-r--r--drivers/media/video/omap3isp/ispresizer.c79
-rw-r--r--drivers/media/video/omap3isp/ispstat.h6
-rw-r--r--drivers/media/video/omap3isp/ispvideo.c114
-rw-r--r--drivers/media/video/omap3isp/ispvideo.h3
-rw-r--r--drivers/media/video/ov6650.c2
-rw-r--r--drivers/media/video/ov9640.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-eeprom.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c10
-rw-r--r--drivers/media/video/pwc/pwc-if.c2
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c23
-rw-r--r--drivers/media/video/pxa_camera.c10
-rw-r--r--drivers/media/video/s2255drv.c27
-rw-r--r--drivers/media/video/s5p-fimc/Makefile6
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c8
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c74
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c2
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.c724
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.h22
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c129
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c34
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c8
-rw-r--r--drivers/media/video/saa7134/saa7134.h3
-rw-r--r--drivers/media/video/saa7164/saa7164-cmd.c2
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c2
-rw-r--r--drivers/media/video/saa7164/saa7164-encoder.c2
-rw-r--r--drivers/media/video/saa7164/saa7164-fw.c2
-rw-r--r--drivers/media/video/saa7164/saa7164-types.h2
-rw-r--r--drivers/media/video/saa7164/saa7164-vbi.c2
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c158
-rw-r--r--drivers/media/video/sh_mobile_csi2.c11
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c2
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h2
-rw-r--r--drivers/media/video/soc_camera.c84
-rw-r--r--drivers/media/video/soc_mediabus.c265
-rw-r--r--drivers/media/video/tcm825x.c4
-rw-r--r--drivers/media/video/tda9840.c2
-rw-r--r--drivers/media/video/tea6415c.c2
-rw-r--r--drivers/media/video/tea6420.c2
-rw-r--r--drivers/media/video/tvaudio.c10
-rw-r--r--drivers/media/video/tveeprom.c32
-rw-r--r--drivers/media/video/upd64031a.c2
-rw-r--r--drivers/media/video/upd64083.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c33
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.h2
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c165
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c8
-rw-r--r--drivers/media/video/usbvision/usbvision.h6
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c367
-rw-r--r--drivers/media/video/uvc/uvc_driver.c28
-rw-r--r--drivers/media/video/uvc/uvc_queue.c34
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c68
-rw-r--r--drivers/media/video/uvc/uvc_video.c8
-rw-r--r--drivers/media/video/uvc/uvcvideo.h64
-rw-r--r--drivers/media/video/v4l2-dev.c33
-rw-r--r--drivers/media/video/v4l2-device.c5
-rw-r--r--drivers/media/video/v4l2-ioctl.c2
-rw-r--r--drivers/media/video/v4l2-subdev.c14
-rw-r--r--drivers/media/video/via-camera.c1
-rw-r--r--drivers/media/video/videobuf-dma-contig.c2
-rw-r--r--drivers/media/video/videobuf2-core.c17
-rw-r--r--drivers/media/video/videobuf2-dma-contig.c2
-rw-r--r--drivers/media/video/vpx3220.c2
-rw-r--r--drivers/media/video/zoran/videocodec.h2
-rw-r--r--drivers/media/video/zoran/zoran.h2
-rw-r--r--drivers/media/video/zoran/zoran_card.c10
-rw-r--r--drivers/media/video/zoran/zoran_driver.c2
167 files changed, 5153 insertions, 1147 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4498b944dec8..3be180b3ba27 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -128,10 +128,10 @@ config VIDEO_IR_I2C
# Encoder / Decoder module configuration
#
-menu "Encoders/decoders and other helper chips"
+menu "Encoders, decoders, sensors and other helper chips"
visible if !VIDEO_HELPER_CHIPS_AUTO
-comment "Audio decoders"
+comment "Audio decoders, processors and mixers"
config VIDEO_TVAUDIO
tristate "Simple audio decoder chips"
@@ -210,15 +210,6 @@ config VIDEO_CS53L32A
To compile this driver as a module, choose M here: the
module will be called cs53l32a.
-config VIDEO_M52790
- tristate "Mitsubishi M52790 A/V switch"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Mitsubishi M52790 A/V switch.
-
- To compile this driver as a module, choose M here: the
- module will be called m52790.
-
config VIDEO_TLV320AIC23B
tristate "Texas Instruments TLV320AIC23B audio codec"
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
@@ -321,29 +312,6 @@ config VIDEO_KS0127
To compile this driver as a module, choose M here: the
module will be called ks0127.
-config VIDEO_OV7670
- tristate "OmniVision OV7670 sensor support"
- depends on I2C && VIDEO_V4L2
- ---help---
- This is a Video4Linux2 sensor-level driver for the OmniVision
- OV7670 VGA camera. It currently only works with the M88ALP01
- controller.
-
-config VIDEO_MT9V011
- tristate "Micron mt9v011 sensor support"
- depends on I2C && VIDEO_V4L2
- ---help---
- This is a Video4Linux2 sensor-level driver for the Micron
- mt0v011 1.3 Mpixel camera. It currently only works with the
- em28xx driver.
-
-config VIDEO_TCM825X
- tristate "TCM825x camera sensor support"
- depends on I2C && VIDEO_V4L2
- ---help---
- This is a driver for the Toshiba TCM825x VGA camera sensor.
- It is used for example in Nokia N800.
-
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L2 && I2C
@@ -362,15 +330,6 @@ config VIDEO_SAA711X
To compile this driver as a module, choose M here: the
module will be called saa7115.
-config VIDEO_SAA717X
- tristate "Philips SAA7171/3/4 audio/video decoders"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7171/3/4 audio/video decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa717x.
-
config VIDEO_SAA7191
tristate "Philips SAA7191 video decoder"
depends on VIDEO_V4L2 && I2C
@@ -420,6 +379,15 @@ config VIDEO_VPX3220
comment "Video and audio decoders"
+config VIDEO_SAA717X
+ tristate "Philips SAA7171/3/4 audio/video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7171/3/4 audio/video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa717x.
+
source "drivers/media/video/cx25840/Kconfig"
comment "MPEG video encoders"
@@ -474,15 +442,6 @@ config VIDEO_ADV7175
To compile this driver as a module, choose M here: the
module will be called adv7175.
-config VIDEO_THS7303
- tristate "THS7303 Video Amplifier"
- depends on I2C
- help
- Support for TI THS7303 video amplifier
-
- To compile this driver as a module, choose M here: the
- module will be called ths7303.
-
config VIDEO_ADV7343
tristate "ADV7343 video encoder"
depends on I2C
@@ -498,6 +457,38 @@ config VIDEO_AK881X
help
Video output driver for AKM AK8813 and AK8814 TV encoders
+comment "Camera sensor devices"
+
+config VIDEO_OV7670
+ tristate "OmniVision OV7670 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV7670 VGA camera. It currently only works with the M88ALP01
+ controller.
+
+config VIDEO_MT9V011
+ tristate "Micron mt9v011 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ mt0v011 1.3 Mpixel camera. It currently only works with the
+ em28xx driver.
+
+config VIDEO_MT9V032
+ tristate "Micron MT9V032 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ MT9V032 752x480 CMOS sensor.
+
+config VIDEO_TCM825X
+ tristate "TCM825x camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a driver for the Toshiba TCM825x VGA camera sensor.
+ It is used for example in Nokia N800.
+
comment "Video improvement chips"
config VIDEO_UPD64031A
@@ -523,6 +514,26 @@ config VIDEO_UPD64083
To compile this driver as a module, choose M here: the
module will be called upd64083.
+comment "Miscelaneous helper chips"
+
+config VIDEO_THS7303
+ tristate "THS7303 Video Amplifier"
+ depends on I2C
+ help
+ Support for TI THS7303 video amplifier
+
+ To compile this driver as a module, choose M here: the
+ module will be called ths7303.
+
+config VIDEO_M52790
+ tristate "Mitsubishi M52790 A/V switch"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Mitsubishi M52790 A/V switch.
+
+ To compile this driver as a module, choose M here: the
+ module will be called m52790.
+
endmenu # encoder / decoder chips
config VIDEO_SH_VOU
@@ -682,7 +693,7 @@ config VIDEO_TIMBERDALE
select VIDEO_ADV7180
select VIDEOBUF_DMA_CONTIG
---help---
- Add support for the Video In peripherial of the timberdale FPGA.
+ Add support for the Video In peripherial of the timberdale FPGA.
source "drivers/media/video/cx88/Kconfig"
@@ -875,7 +886,7 @@ config MX3_VIDEO
config VIDEO_MX3
tristate "i.MX3x Camera Sensor Interface driver"
depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
- select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF2_DMA_CONTIG
select MX3_VIDEO
---help---
This is a v4l2 driver for the i.MX3x Camera Sensor Interface
@@ -916,7 +927,7 @@ config VIDEO_OMAP2
This is a v4l2 driver for the TI OMAP2 camera capture interface
config VIDEO_MX2_HOSTSUPPORT
- bool
+ bool
config VIDEO_MX2
tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
@@ -927,6 +938,26 @@ config VIDEO_MX2
This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
Interface
+config VIDEO_SAMSUNG_S5P_FIMC
+ tristate "Samsung S5P and EXYNOS4 camera host interface driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ This is a v4l2 driver for Samsung S5P and EXYNOS4 camera
+ host interface and video postprocessor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called s5p-fimc.
+
+config VIDEO_S5P_MIPI_CSIS
+ tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
+ depends on VIDEO_V4L2 && PM_RUNTIME && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called s5p-csis.
#
# USB Multimedia device configuration
@@ -983,7 +1014,7 @@ config USB_STKWEBCAM
Supported devices are typically found in some Asus laptops,
with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
may be supported by the stk11xx driver, from which this is
- derived, see <http://sourceforge.net/projects/syntekdriver/>
+ derived, see <http://sourceforge.net/projects/syntekdriver/>
To compile this driver as a module, choose M here: the
module will be called stkwebcam.
@@ -1022,13 +1053,5 @@ config VIDEO_MEM2MEM_TESTDEV
This is a virtual test device for the memory-to-memory driver
framework.
-config VIDEO_SAMSUNG_S5P_FIMC
- tristate "Samsung S5P FIMC (video postprocessor) driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
- select VIDEOBUF2_DMA_CONTIG
- select V4L2_MEM2MEM_DEV
- help
- This is a v4l2 driver for the S5P camera interface
- (video postprocessor)
endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ace5d8b57221..9519160c2e01 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
@@ -164,6 +165,7 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
+
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 6ad83a15d073..c03eb29a9ee6 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -502,7 +502,7 @@ static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
/* Get the next buffer */
*buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
- /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
outp = videobuf_to_vmalloc(&(*buf)->vb);
memset(outp, 0x00, (*buf)->vb.size);
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 242f0d512238..3c9e6c7e7b52 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -2244,8 +2244,8 @@ struct tvcard bttv_tvcards[] = {
},
[BTTV_BOARD_PICOLO_TETRA_CHIP] = {
/*Eric DEBIEF <debief@telemsa.com>*/
- /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
- /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
+ /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controlled*/
+ /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
/*0x79 in bttv.h*/
.name = "Euresys Picolo Tetra",
.video_inputs = 4,
@@ -4567,7 +4567,7 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input)
* at one input while the monitor is looking at another.
*
* Since I've couldn't be bothered figuring out how to add an
- * independant muxsel for the monitor bus, I've just set it to
+ * independent muxsel for the monitor bus, I've just set it to
* whatever the card is looking at.
*
* OUT0 of the TDA8540's is connected to MUX0 (0x03)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 91399c94cd18..a97cf2750bd9 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -4303,7 +4303,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
goto fail0;
}
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+ btv->revision = dev->revision;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
bttv_num,btv->id, btv->revision, pci_name(dev));
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index fd604d32bbb9..13ce72c04b33 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -3,7 +3,7 @@
bttv-gpio.c -- gpio sub drivers
sysfs-based sub driver interface for bttv
- mainly intented for gpio access
+ mainly intended for gpio access
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 55ffd60ffa7f..664703398493 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -383,7 +383,7 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
* causes the device to die.
* Use a busy-wait because we often send a large quantity of small
* commands at-once; using msleep() would cause a lot of context
- * switches which take longer than 2ms, resulting in a noticable
+ * switches which take longer than 2ms, resulting in a noticeable
* boot-time and capture-start delays.
*/
mdelay(2);
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 5111bbcefad5..0073a8c55336 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1313,7 +1313,7 @@ static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p)
static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio)
{
struct camera_data *cam = video_drvdata(file);
- struct cpia2_fh *fh = fh;
+ struct cpia2_fh *fh = _fh;
if (cam->streaming && prio != fh->prio &&
fh->prio == V4L2_PRIORITY_RECORD)
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index d9d2f6ad6ffb..53b3c7702573 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -2,6 +2,7 @@ config VIDEO_CX18
tristate "Conexant cx23418 MPEG encoder support"
depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
select I2C_ALGOBIT
+ select VIDEOBUF_VMALLOC
depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -9,6 +10,9 @@ config VIDEO_CX18
select VIDEO_CS5345
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
---help---
This is a video4linux driver for Conexant cx23418 based
PCI combo video recorder devices.
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index 188c9c3d2db1..e9c69d9c9e4a 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -109,7 +109,7 @@ struct cx18_av_state {
int is_initialized;
/*
- * The VBI slicer starts operating and counting lines, begining at
+ * The VBI slicer starts operating and counting lines, beginning at
* 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
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 68ad1963f421..c07c849b1aaf 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -39,6 +39,16 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
.tv = { 0x61, 0x60, I2C_CLIENT_END },
};
+/*
+ * usual i2c tuner addresses to probe with additional demod address for
+ * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too).
+ */
+static struct cx18_card_tuner_i2c cx18_i2c_nxp = {
+ .radio = { I2C_CLIENT_END },
+ .demod = { 0x42, 0x43, I2C_CLIENT_END },
+ .tv = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
@@ -131,15 +141,15 @@ static const struct cx18_card cx18_card_hvr1600_s5h1411 = {
.tune_lane = 0,
.initial_emrs = 0,
},
- .gpio_init.initial_value = 0x3001,
- .gpio_init.direction = 0x3001,
+ .gpio_init.initial_value = 0x3801,
+ .gpio_init.direction = 0x3801,
.gpio_i2c_slave_reset = {
- .active_lo_mask = 0x3001,
+ .active_lo_mask = 0x3801,
.msecs_asserted = 10,
.msecs_recovery = 40,
.ir_reset_mask = 0x0001,
},
- .i2c = &cx18_i2c_std,
+ .i2c = &cx18_i2c_nxp,
};
static const struct cx18_card cx18_card_hvr1600_samsung = {
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index 3e750068f275..add7391ecaba 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -109,7 +109,7 @@ struct cx18_card_tuner {
struct cx18_card_tuner_i2c {
unsigned short radio[2];/* radio tuner i2c address to probe */
- unsigned short demod[2];/* demodulator i2c address to probe */
+ unsigned short demod[3];/* demodulator i2c address to probe */
unsigned short tv[4]; /* tv tuner i2c addresses to probe */
};
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 321c1b79794c..9e2f870f4258 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -423,7 +423,16 @@ static void cx18_process_eeprom(struct cx18 *cx)
return;
/* autodetect tuner standard */
- if (tv.tuner_formats & V4L2_STD_PAL) {
+#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \
+ V4L2_STD_MN | \
+ V4L2_STD_PAL_I | \
+ V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \
+ V4L2_STD_DK)
+ if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL)
+ == TVEEPROM_TUNER_FORMAT_ALL) {
+ CX18_DEBUG_INFO("Worldwide tuner detected\n");
+ cx->std = V4L2_STD_ALL;
+ } else if (tv.tuner_formats & V4L2_STD_PAL) {
CX18_DEBUG_INFO("PAL tuner detected\n");
cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
} else if (tv.tuner_formats & V4L2_STD_NTSC) {
@@ -818,7 +827,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev);
+ cx->card_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 64 && cx18_pci_latency) {
@@ -1001,7 +1010,15 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
if (cx->card->hw_all & CX18_HW_TVEEPROM) {
/* Based on the model number the cardtype may be changed.
The PCI IDs are not always reliable. */
+ const struct cx18_card *orig_card = cx->card;
cx18_process_eeprom(cx);
+
+ if (cx->card != orig_card) {
+ /* Changed the cardtype; re-reset the I2C chips */
+ cx18_gpio_init(cx);
+ cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
+ core, reset, (u32) CX18_GPIO_RESET_I2C);
+ }
}
if (cx->card->comment)
CX18_INFO("%s", cx->card->comment);
@@ -1087,6 +1104,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
are not. */
cx->tuner_std = cx->std;
+ if (cx->std == V4L2_STD_ALL)
+ cx->std = V4L2_STD_NTSC_M;
retval = cx18_streams_setup(cx);
if (retval) {
@@ -1133,6 +1152,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
int fw_retry_count = 3;
struct v4l2_frequency vf;
struct cx18_open_id fh;
+ v4l2_std_id std;
fh.cx = cx;
@@ -1220,7 +1240,8 @@ int cx18_init_on_first_open(struct cx18 *cx)
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
in one place. */
cx->std++; /* Force full standard initialization */
- cx18_s_std(NULL, &fh, &cx->tuner_std);
+ std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
+ cx18_s_std(NULL, &fh, &std);
cx18_s_frequency(NULL, &fh, &vf);
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b86a740c68df..086427288de8 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -65,6 +65,10 @@
#include "dvb_net.h"
#include "dvbdev.h"
+/* Videobuf / YUV support */
+#include <media/videobuf-core.h>
+#include <media/videobuf-vmalloc.h>
+
#ifndef CONFIG_PCI
# error "This driver requires kernel PCI support."
#endif
@@ -403,6 +407,23 @@ struct cx18_stream {
struct cx18_queue q_idle; /* idle - not in rotation */
struct work_struct out_work_order;
+
+ /* Videobuf for YUV video */
+ u32 pixelformat;
+ struct list_head vb_capture; /* video capture queue */
+ spinlock_t vb_lock;
+ struct timer_list vb_timeout;
+
+ struct videobuf_queue vbuf_q;
+ spinlock_t vbuf_q_lock; /* Protect vbuf_q */
+ enum v4l2_buf_type vb_type;
+};
+
+struct cx18_videobuf_buffer {
+ /* Common video buffer sub-system struct */
+ struct videobuf_buffer vb;
+ v4l2_std_id tvnorm; /* selected tv norm */
+ u32 bytes_used;
};
struct cx18_open_id {
@@ -410,6 +431,10 @@ struct cx18_open_id {
u32 open_id;
int type;
struct cx18 *cx;
+
+ struct videobuf_queue vbuf_q;
+ spinlock_t s_lock; /* Protect vbuf_q */
+ enum v4l2_buf_type vb_type;
};
static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index e9802d99439b..07411f34885a 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -597,6 +597,13 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
mutex_unlock(&cx->serialize_lock);
if (rc)
return rc;
+
+ if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+ return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+
return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
}
@@ -622,6 +629,15 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_FILE("Encoder poll started capture\n");
}
+ if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+ int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);
+ if (eof && videobuf_poll == POLLERR)
+ return POLLHUP;
+ else
+ return videobuf_poll;
+ }
+
/* add stream's waitq to the poll list */
CX18_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
@@ -633,6 +649,58 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
return 0;
}
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+
+ /* Start a capture if there is none */
+ if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ int rc;
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc) {
+ CX18_DEBUG_INFO(
+ "Could not start capture for %s (%d)\n",
+ s->name, rc);
+ return -EINVAL;
+ }
+ CX18_DEBUG_FILE("Encoder mmap started capture\n");
+ }
+
+ return videobuf_mmap_mapper(&s->vbuf_q, vma);
+ }
+
+ return -EINVAL;
+}
+
+void cx18_vb_timeout(unsigned long data)
+{
+ struct cx18_stream *s = (struct cx18_stream *)data;
+ struct cx18_videobuf_buffer *buf;
+ unsigned long flags;
+
+ /* Return all of the buffers in error state, so the vbi/vid inode
+ * can return from blocking.
+ */
+ spin_lock_irqsave(&s->vb_lock, flags);
+ while (!list_empty(&s->vb_capture)) {
+ buf = list_entry(s->vb_capture.next,
+ struct cx18_videobuf_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ }
+ spin_unlock_irqrestore(&s->vb_lock, flags);
+}
+
void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
{
struct cx18 *cx = id->cx;
@@ -716,6 +784,8 @@ int cx18_v4l2_close(struct file *filp)
cx18_release_stream(s);
} else {
cx18_stop_capture(id, 0);
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV)
+ videobuf_mmap_free(&id->vbuf_q);
}
kfree(id);
mutex_unlock(&cx->serialize_lock);
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
index 5c8fcb884f0a..b9e5110ad043 100644
--- a/drivers/media/video/cx18/cx18-fileops.h
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -33,6 +33,8 @@ int cx18_start_capture(struct cx18_open_id *id);
void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
void cx18_mute(struct cx18 *cx);
void cx18_unmute(struct cx18 *cx);
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
+void cx18_vb_timeout(unsigned long data);
/* Shared with cx18-alsa module */
int cx18_claim_stream(struct cx18_open_id *id, int type);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 86c30b9963e5..1933d4d11bf2 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -150,6 +150,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
{
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
pixfmt->width = cx->cxhdl.width;
@@ -158,9 +159,13 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
pixfmt->field = V4L2_FIELD_INTERLACED;
pixfmt->priv = 0;
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
- pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
- pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ pixfmt->pixelformat = s->pixelformat;
+ /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+ UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+ if (s->pixelformat == V4L2_PIX_FMT_HM12)
+ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ else
+ pixfmt->sizeimage = pixfmt->height * 720 * 2;
pixfmt->bytesperline = 720;
} else {
pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -237,7 +242,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
h = min(h, cx->is_50hz ? 576 : 480);
h = max(h, min_h);
- cx18_g_fmt_vid_cap(file, fh, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
return 0;
@@ -274,6 +278,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
struct v4l2_mbus_framefmt mbus_fmt;
+ struct cx18_stream *s = &cx->streams[id->type];
int ret;
int w, h;
@@ -283,12 +288,15 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
- if (cx->cxhdl.width == w && cx->cxhdl.height == h)
+ if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
+ s->pixelformat == fmt->fmt.pix.pixelformat)
return 0;
if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+ s->pixelformat = fmt->fmt.pix.pixelformat;
+
mbus_fmt.width = cx->cxhdl.width = w;
mbus_fmt.height = cx->cxhdl.height = h;
mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
@@ -312,7 +320,7 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
/*
* Set the digitizer registers for raw active VBI.
- * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
+ * Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid
* calling conditions
*/
ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi);
@@ -540,16 +548,19 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_fmtdesc *fmt)
{
- static struct v4l2_fmtdesc formats[] = {
+ static const struct v4l2_fmtdesc formats[] = {
{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
"HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
},
{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
"MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
- }
+ },
+ { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+ "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 }
+ },
};
- if (fmt->index > 1)
+ if (fmt->index > ARRAY_SIZE(formats) - 1)
return -EINVAL;
*fmt = formats[fmt->index];
return 0;
@@ -863,6 +874,117 @@ static int cx18_g_enc_index(struct file *file, void *fh,
return 0;
}
+static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
+{
+ struct videobuf_queue *q = NULL;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ switch (s->vb_type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ q = &s->vbuf_q;
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ break;
+ default:
+ break;
+ }
+ return q;
+}
+
+static int cx18_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ /* Start the hardware only if we're the video device */
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+ return -EINVAL;
+
+ /* Establish a buffer timeout */
+ mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+ return videobuf_streamon(cx18_vb_queue(id));
+}
+
+static int cx18_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ /* Start the hardware only if we're the video device */
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+ return -EINVAL;
+
+ return videobuf_streamoff(cx18_vb_queue(id));
+}
+
+static int cx18_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_reqbufs(cx18_vb_queue(id), rb);
+}
+
+static int cx18_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_querybuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_qbuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
+}
+
static int cx18_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
@@ -1081,6 +1203,12 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_s_register = cx18_s_register,
#endif
.vidioc_default = cx18_default,
+ .vidioc_streamon = cx18_streamon,
+ .vidioc_streamoff = cx18_streamoff,
+ .vidioc_reqbufs = cx18_reqbufs,
+ .vidioc_querybuf = cx18_querybuf,
+ .vidioc_qbuf = cx18_qbuf,
+ .vidioc_dqbuf = cx18_dqbuf,
};
void cx18_set_funcs(struct video_device *vdev)
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 9605d54bd083..c07191e09fcb 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW),
@@ -158,6 +159,60 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
}
}
+static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
+ struct cx18_mdl *mdl)
+{
+ struct cx18_videobuf_buffer *vb_buf;
+ struct cx18_buffer *buf;
+ u8 *p;
+ u32 offset = 0;
+ int dispatch = 0;
+
+ if (mdl->bytesused == 0)
+ return;
+
+ /* Acquire a videobuf buffer, clone to and and release it */
+ spin_lock(&s->vb_lock);
+ if (list_empty(&s->vb_capture))
+ goto out;
+
+ vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer,
+ vb.queue);
+
+ p = videobuf_to_vmalloc(&vb_buf->vb);
+ if (!p)
+ goto out;
+
+ offset = vb_buf->bytes_used;
+ list_for_each_entry(buf, &mdl->buf_list, list) {
+ if (buf->bytesused == 0)
+ break;
+
+ if ((offset + buf->bytesused) <= vb_buf->vb.bsize) {
+ memcpy(p + offset, buf->buf, buf->bytesused);
+ offset += buf->bytesused;
+ vb_buf->bytes_used += buf->bytesused;
+ }
+ }
+
+ /* If we've filled the buffer as per the callers res then dispatch it */
+ if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) {
+ dispatch = 1;
+ vb_buf->bytes_used = 0;
+ }
+
+ if (dispatch) {
+ vb_buf->vb.ts = ktime_to_timeval(ktime_get());
+ list_del(&vb_buf->vb.queue);
+ vb_buf->vb.state = VIDEOBUF_DONE;
+ wake_up(&vb_buf->vb.done);
+ }
+
+ mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+out:
+ spin_unlock(&s->vb_lock);
+}
static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s,
struct cx18_mdl *mdl)
@@ -263,6 +318,9 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
} else {
cx18_enqueue(s, mdl, &s->q_full);
}
+ } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) {
+ cx18_mdl_send_to_videobuf(s, mdl);
+ cx18_enqueue(s, mdl, &s->q_free);
} else {
cx18_enqueue(s, mdl, &s->q_full);
if (s->type == CX18_ENC_STREAM_TYPE_IDX)
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index c6e2ca3b1149..852f420fd271 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -44,6 +44,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
.unlocked_ioctl = cx18_v4l2_ioctl,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
+ .mmap = cx18_v4l2_mmap,
};
/* offset from 0 to register ts v4l2 minors on */
@@ -97,6 +98,141 @@ static struct {
},
};
+
+void cx18_dma_free(struct videobuf_queue *q,
+ struct cx18_stream *s, struct cx18_videobuf_buffer *buf)
+{
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int cx18_prepare_buffer(struct videobuf_queue *q,
+ struct cx18_stream *s,
+ struct cx18_videobuf_buffer *buf,
+ u32 pixelformat,
+ unsigned int width, unsigned int height,
+ enum v4l2_field field)
+{
+ struct cx18 *cx = s->cx;
+ int rc = 0;
+
+ /* check settings */
+ buf->bytes_used = 0;
+
+ if ((width < 48) || (height < 32))
+ return -EINVAL;
+
+ buf->vb.size = (width * height * 2);
+ if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+ return -EINVAL;
+
+ /* alloc + fill struct (if changed) */
+ if (buf->vb.width != width || buf->vb.height != height ||
+ buf->vb.field != field || s->pixelformat != pixelformat ||
+ buf->tvnorm != cx->std) {
+
+ buf->vb.width = width;
+ buf->vb.height = height;
+ buf->vb.field = field;
+ buf->tvnorm = cx->std;
+ s->pixelformat = pixelformat;
+
+ cx18_dma_free(q, s, buf);
+ }
+
+ if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+ return -EINVAL;
+
+ if (buf->vb.field == 0)
+ buf->vb.field = V4L2_FIELD_INTERLACED;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ buf->vb.width = width;
+ buf->vb.height = height;
+ buf->vb.field = field;
+ buf->tvnorm = cx->std;
+ s->pixelformat = pixelformat;
+
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (rc != 0)
+ goto fail;
+ }
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ cx18_dma_free(q, s, buf);
+ return rc;
+
+}
+
+/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576)
+ 1440 is a single line of 4:2:2 YUV at 720 luma samples wide
+*/
+#define VB_MIN_BUFFERS 32
+#define VB_MIN_BUFSIZE 4147200
+
+static int buffer_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx18_stream *s = q->priv_data;
+ struct cx18 *cx = s->cx;
+
+ *size = 2 * cx->cxhdl.width * cx->cxhdl.height;
+ if (*count == 0)
+ *count = VB_MIN_BUFFERS;
+
+ while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE)
+ (*count)--;
+
+ q->field = V4L2_FIELD_INTERLACED;
+ q->last = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx18_videobuf_buffer *buf =
+ container_of(vb, struct cx18_videobuf_buffer, vb);
+ struct cx18_stream *s = q->priv_data;
+ struct cx18 *cx = s->cx;
+
+ return cx18_prepare_buffer(q, s, buf, s->pixelformat,
+ cx->cxhdl.width, cx->cxhdl.height, field);
+}
+
+static void buffer_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx18_videobuf_buffer *buf =
+ container_of(vb, struct cx18_videobuf_buffer, vb);
+ struct cx18_stream *s = q->priv_data;
+
+ cx18_dma_free(q, s, buf);
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct cx18_videobuf_buffer *buf =
+ container_of(vb, struct cx18_videobuf_buffer, vb);
+ struct cx18_stream *s = q->priv_data;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+
+ list_add_tail(&buf->vb.queue, &s->vb_capture);
+}
+
+static struct videobuf_queue_ops cx18_videobuf_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
static void cx18_stream_init(struct cx18 *cx, int type)
{
struct cx18_stream *s = &cx->streams[type];
@@ -132,6 +268,26 @@ static void cx18_stream_init(struct cx18 *cx, int type)
cx18_queue_init(&s->q_idle);
INIT_WORK(&s->out_work_order, cx18_out_work_handler);
+
+ INIT_LIST_HEAD(&s->vb_capture);
+ s->vb_timeout.function = cx18_vb_timeout;
+ s->vb_timeout.data = (unsigned long)s;
+ init_timer(&s->vb_timeout);
+ spin_lock_init(&s->vb_lock);
+ if (type == CX18_ENC_STREAM_TYPE_YUV) {
+ spin_lock_init(&s->vbuf_q_lock);
+
+ s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops,
+ &cx->pci_dev->dev, &s->vbuf_q_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx18_videobuf_buffer),
+ s, &cx->serialize_lock);
+
+ /* Assume the previous pixel default */
+ s->pixelformat = V4L2_PIX_FMT_HM12;
+ }
}
static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -350,9 +506,17 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
/* No struct video_device, but can have buffers allocated */
if (type == CX18_ENC_STREAM_TYPE_IDX) {
+ /* If the module params didn't inhibit IDX ... */
if (cx->stream_buffers[type] != 0) {
cx->stream_buffers[type] = 0;
- cx18_stream_free(&cx->streams[type]);
+ /*
+ * Before calling cx18_stream_free(),
+ * check if the IDX stream was actually set up.
+ * Needed, since the cx18_probe() error path
+ * exits through here as well as normal clean up
+ */
+ if (cx->streams[type].buffers != 0)
+ cx18_stream_free(&cx->streams[type]);
}
continue;
}
@@ -364,6 +528,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
if (vdev == NULL)
continue;
+ if (type == CX18_ENC_STREAM_TYPE_YUV)
+ videobuf_mmap_free(&cx->streams[type].vbuf_q);
+
cx18_stream_free(&cx->streams[type]);
/* Unregister or release device */
@@ -573,7 +740,10 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
* Set the MDL size to the exact size needed for one frame.
* Use enough buffers per MDL to cover the MDL size
*/
- s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
+ if (s->pixelformat == V4L2_PIX_FMT_HM12)
+ s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
+ else
+ s->mdl_size = 720 * s->cx->cxhdl.height * 2;
s->bufs_per_mdl = s->mdl_size / s->buf_size;
if (s->mdl_size % s->buf_size)
s->bufs_per_mdl++;
@@ -721,6 +891,19 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
(v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
+
+ /* Enable the Video Format Converter for UYVY 4:2:2 support,
+ * rather than the default HM12 Macroblovk 4:2:0 support.
+ */
+ if (captype == CAPTURE_CHANNEL_TYPE_YUV) {
+ if (s->pixelformat == V4L2_PIX_FMT_UYVY)
+ cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+ s->handle, 1);
+ else
+ /* If in doubt, default to HM12 */
+ cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+ s->handle, 0);
+ }
}
if (atomic_read(&cx->tot_capturing) == 0) {
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
index 582227522cf0..6d3121ff45a2 100644
--- a/drivers/media/video/cx18/cx18-vbi.c
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -29,7 +29,7 @@
/*
* Raster Reference/Protection (RP) bytes, used in Start/End Active
* Video codes emitted from the digitzer in VIP 1.x mode, that flag the start
- * of VBI sample or VBI ancilliary data regions in the digitial ratser line.
+ * of VBI sample or VBI ancillary data regions in the digitial ratser line.
*
* Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
*/
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
index 3e1aec4bcfde..cd189b6bbe20 100644
--- a/drivers/media/video/cx18/cx18-version.h
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -24,7 +24,7 @@
#define CX18_DRIVER_NAME "cx18"
#define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 4
+#define CX18_DRIVER_VERSION_MINOR 5
#define CX18_DRIVER_VERSION_PATCHLEVEL 0
#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 935f557acbd0..767a8d23e3f2 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -342,6 +342,12 @@
ReturnCode */
#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022)
+/* Description: Set VFC parameters
+ IN[0] - task handle
+ IN[1] - VFC enable flag, 1 - enable, 0 - disable
+*/
+#define CX18_CPU_SET_VFC_PARAM (CPU_CMD_MASK_CAPTURE | 0x0023)
+
/* Below is the list of commands related to the data exchange */
#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000)
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
index 62843d39817c..280df43ca446 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -2577,7 +2577,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
break;
case 6: /* ts1 parallel mode */
- cx231xx_info("%s: set ts1 parrallel mode registers\n",
+ cx231xx_info("%s: set ts1 parallel mode registers\n",
__func__);
status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400);
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index f49230d170e6..22703815a31f 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -401,6 +401,44 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_KWORLD_UB430_USB_HYBRID] = {
+ .name = "Kworld UB430 USB Hybrid",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x11, /* According with PV cxPolaris.inf file */
+ .tuner_sif_gpio = -1,
+ .tuner_scl_gpio = -1,
+ .tuner_sda_gpio = -1,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 2,
+ .demod_i2c_master = 1,
+ .ir_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x10,
+ .norm = V4L2_STD_PAL_M,
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
[CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = {
.name = "Pixelview PlayTV USB Hybrid",
.tuner_type = TUNER_NXP_TDA18271,
@@ -469,6 +507,31 @@ struct cx231xx_board cx231xx_boards[] = {
}
},
},
+
+ [CX231XX_BOARD_ICONBIT_U100] = {
+ .name = "Iconbit Analog Stick U100 FM",
+ .tuner_type = TUNER_ABSENT,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x1C,
+ .gpio_pin_status_mask = 0x4001000,
+
+ .input = {{
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -500,6 +563,10 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
{USB_DEVICE(USB_VID_PIXELVIEW, 0x5014),
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
+ {USB_DEVICE(0x1b80, 0xe424),
+ .driver_info = CX231XX_BOARD_KWORLD_UB430_USB_HYBRID},
+ {USB_DEVICE(0x1f4d, 0x0237),
+ .driver_info = CX231XX_BOARD_ICONBIT_U100},
{},
};
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c
index 363aa6004221..da9a4a0aab79 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -704,6 +704,7 @@ static int dvb_init(struct cx231xx *dev)
break;
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+ case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n",
__func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c
index 1d914488dbb3..1c7a4daafecf 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/video/cx231xx/cx231xx-vbi.c
@@ -631,7 +631,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
/* 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 */
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
outp = videobuf_to_vmalloc(&(*buf)->vb);
memset(outp, 0, (*buf)->vb.size);
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index ffd5af914c44..a69c24d8db06 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -309,7 +309,7 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
/* 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 */
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
outp = videobuf_to_vmalloc(&(*buf)->vb);
memset(outp, 0, (*buf)->vb.size);
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h
index bd4a9cf29577..46dd84067816 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/video/cx231xx/cx231xx.h
@@ -65,6 +65,8 @@
#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
#define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10
#define CX231XX_BOARD_PV_XCAPTURE_USB 11
+#define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12
+#define CX231XX_BOARD_ICONBIT_U100 13
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index 3b6e7f28568e..caab1bfb79e2 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -22,6 +22,7 @@ config VIDEO_CX23885
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_STV0900 if !DVB_FE_CUSTOMISE
select DVB_DS3000 if !DVB_FE_CUSTOMISE
+ select DVB_STV0367 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
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
index 209b971bd267..c9f15d6dec40 100644
--- a/drivers/media/video/cx23885/cimax2.c
+++ b/drivers/media/video/cx23885/cimax2.c
@@ -449,7 +449,7 @@ int netup_ci_init(struct cx23885_tsport *port)
0x04, /* ack active low */
0x00, /* LOCK = 0 */
0x33, /* serial mode, rising in, rising out, MSB first*/
- 0x31, /* syncronization */
+ 0x31, /* synchronization */
};
int ret;
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index ea88722cb4ab..2354336862cf 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -1399,6 +1399,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
else
altera_init(&netup_config, fw);
+ release_firmware(fw);
break;
}
}
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 9933810b4e33..64d9b2136ff6 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -2045,7 +2045,7 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
}
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 8db2797bc7c3..c186473fc570 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -214,7 +214,7 @@ struct cx23885_board {
/* Vendors can and do run the PCIe bridge at different
* clock rates, driven physically by crystals on the PCBs.
- * The core has to accomodate this. This allows the user
+ * The core has to accommodate this. This allows the user
* to add new boards with new frequencys. The value is
* expressed in Hz.
*
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 35796e035247..b7ee2ae70583 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2004 Ulf Eklund
*
- * Based on the saa7115 driver and on the first verison of Chris Kennedy's
+ * Based on the saa7115 driver and on the first version of Chris Kennedy's
* cx25840 driver.
*
* Changes by Tyler Trafford <tatrafford@comcast.net>
@@ -445,7 +445,7 @@ static void cx25840_initialize(struct i2c_client *client)
cx25840_write(client, 0x918, 0xa0);
cx25840_write(client, 0x919, 0x01);
- /* stereo prefered */
+ /* stereo preferred */
cx25840_write(client, 0x809, 0x04);
/* AC97 shift */
cx25840_write(client, 0x8cf, 0x0f);
@@ -546,7 +546,7 @@ static void cx23885_initialize(struct i2c_client *client)
* Aux PLL
* Initial setup for audio sample clock:
* 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz
- * Intial I2S output/master clock(?):
+ * Initial I2S output/master clock(?):
* 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
*/
switch (state->id) {
@@ -903,7 +903,7 @@ static void input_change(struct i2c_client *client)
} else if (std & V4L2_STD_PAL) {
/* Autodetect audio standard and audio system */
cx25840_write(client, 0x808, 0xff);
- /* Since system PAL-L is pretty much non-existant and
+ /* Since system PAL-L is pretty much non-existent and
not used by any public broadcast network, force
6.5 MHz carrier to be interpreted as System DK,
this avoids DK audio detection instability */
@@ -1851,7 +1851,7 @@ static u32 get_cx2388x_ident(struct i2c_client *client)
ret = V4L2_IDENT_CX23885_AV;
} else {
/* CX23887 has a broken DIF, but the registers
- * appear valid (but unsed), good enough to detect. */
+ * appear valid (but unused), good enough to detect. */
ret = V4L2_IDENT_CX23887_AV;
}
} else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index bca307eb1e24..11e49bbc4a66 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1060,18 +1060,21 @@ static int mpeg_open(struct file *file)
/* Make sure we can acquire the hardware */
drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
- if (drv) {
- err = drv->request_acquire(drv);
- if(err != 0) {
- dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
- mutex_unlock(&dev->core->lock);
- return err;
- }
+ if (!drv) {
+ dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
+ mutex_unlock(&dev->core->lock);
+ return -ENODEV;
+ }
+
+ err = drv->request_acquire(drv);
+ if (err != 0) {
+ dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
+ mutex_unlock(&dev->core->lock);
+ return err;
}
- if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) {
- if (drv)
- drv->request_release(drv);
+ if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) {
+ drv->request_release(drv);
mutex_unlock(&dev->core->lock);
return -EINVAL;
}
@@ -1080,8 +1083,7 @@ static int mpeg_open(struct file *file)
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
if (NULL == fh) {
- if (drv)
- drv->request_release(drv);
+ drv->request_release(drv);
mutex_unlock(&dev->core->lock);
return -ENOMEM;
}
@@ -1099,7 +1101,7 @@ static int mpeg_open(struct file *file)
cx88_set_scale(dev->core, dev->width, dev->height,
fh->mpegq.field);
- atomic_inc(&dev->core->mpeg_users);
+ dev->core->mpeg_users++;
mutex_unlock(&dev->core->lock);
return 0;
}
@@ -1110,7 +1112,9 @@ static int mpeg_release(struct file *file)
struct cx8802_dev *dev = fh->dev;
struct cx8802_driver *drv = NULL;
- if (dev->mpeg_active && atomic_read(&dev->core->mpeg_users) == 1)
+ mutex_lock(&dev->core->lock);
+
+ if (dev->mpeg_active && dev->core->mpeg_users == 1)
blackbird_stop_codec(dev);
cx8802_cancel_buffers(fh->dev);
@@ -1119,17 +1123,18 @@ static int mpeg_release(struct file *file)
videobuf_mmap_free(&fh->mpegq);
- mutex_lock(&dev->core->lock);
file->private_data = NULL;
kfree(fh);
- mutex_unlock(&dev->core->lock);
/* Make sure we release the hardware */
drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+ WARN_ON(!drv);
if (drv)
drv->request_release(drv);
- atomic_dec(&dev->core->mpeg_users);
+ dev->core->mpeg_users--;
+
+ mutex_unlock(&dev->core->lock);
return 0;
}
@@ -1334,11 +1339,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
blackbird_register_video(dev);
/* initial device configuration: needed ? */
- mutex_lock(&dev->core->lock);
// init_controls(core);
cx88_set_tvnorm(core,core->tvnorm);
cx88_video_mux(core,0);
- mutex_unlock(&dev->core->lock);
return 0;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 7b8c9d3b6efc..c69df7ebb6a7 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -133,6 +133,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
return -EINVAL;
}
+ mutex_lock(&dev->core->lock);
drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
if (drv) {
if (acquire){
@@ -143,6 +144,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
dev->frontends.active_fe_id = 0;
}
}
+ mutex_unlock(&dev->core->lock);
return ret;
}
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index c820e2f53527..3f442003623d 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -524,7 +524,7 @@ void cx88_ir_irq(struct cx88_core *core)
for (todo = 32; todo > 0; todo -= bits) {
ev.pulse = samples & 0x80000000 ? false : true;
bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
- ev.duration = (bits * NSEC_PER_SEC) / (1000 * ir_samplerate);
+ ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
ir_raw_event_store_with_filter(ir->dev, &ev);
samples <<= bits;
}
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index addf9545e9bf..1a7b983f8297 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -78,6 +78,7 @@ static void flush_request_modules(struct cx8802_dev *dev)
static LIST_HEAD(cx8802_devlist);
+static DEFINE_MUTEX(cx8802_mutex);
/* ------------------------------------------------------------------ */
static int cx8802_start_dma(struct cx8802_dev *dev,
@@ -474,7 +475,7 @@ static int cx8802_init_common(struct cx8802_dev *dev)
return -EIO;
}
- pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = dev->pci->revision;
pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->core->name,
@@ -624,13 +625,11 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
if (drv->advise_acquire)
{
- mutex_lock(&drv->core->lock);
core->active_ref++;
if (core->active_type_id == CX88_BOARD_NONE) {
core->active_type_id = drv->type_id;
drv->advise_acquire(drv);
}
- mutex_unlock(&drv->core->lock);
mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
@@ -643,14 +642,12 @@ static int cx8802_request_release(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
- mutex_lock(&drv->core->lock);
if (drv->advise_release && --core->active_ref == 0)
{
drv->advise_release(drv);
core->active_type_id = CX88_BOARD_NONE;
mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
- mutex_unlock(&drv->core->lock);
return 0;
}
@@ -693,6 +690,8 @@ int cx8802_register_driver(struct cx8802_driver *drv)
return err;
}
+ mutex_lock(&cx8802_mutex);
+
list_for_each_entry(dev, &cx8802_devlist, devlist) {
printk(KERN_INFO
"%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
@@ -702,8 +701,10 @@ int cx8802_register_driver(struct cx8802_driver *drv)
/* Bring up a new struct for each driver instance */
driver = kzalloc(sizeof(*drv),GFP_KERNEL);
- if (driver == NULL)
- return -ENOMEM;
+ if (driver == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
/* Snapshot of the driver registration data */
drv->core = dev->core;
@@ -713,21 +714,23 @@ int cx8802_register_driver(struct cx8802_driver *drv)
drv->request_release = cx8802_request_release;
memcpy(driver, drv, sizeof(*driver));
+ mutex_lock(&drv->core->lock);
err = drv->probe(driver);
if (err == 0) {
i++;
- mutex_lock(&drv->core->lock);
list_add_tail(&driver->drvlist, &dev->drvlist);
- mutex_unlock(&drv->core->lock);
} else {
printk(KERN_ERR
"%s/2: cx8802 probe failed, err = %d\n",
dev->core->name, err);
}
-
+ mutex_unlock(&drv->core->lock);
}
- return i ? 0 : -ENODEV;
+ err = i ? 0 : -ENODEV;
+out:
+ mutex_unlock(&cx8802_mutex);
+ return err;
}
int cx8802_unregister_driver(struct cx8802_driver *drv)
@@ -741,6 +744,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+ mutex_lock(&cx8802_mutex);
+
list_for_each_entry(dev, &cx8802_devlist, devlist) {
printk(KERN_INFO
"%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
@@ -748,6 +753,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
dev->pci->subsystem_device, dev->core->board.name,
dev->core->boardnr);
+ mutex_lock(&dev->core->lock);
+
list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) {
/* only unregister the correct driver type */
if (d->type_id != drv->type_id)
@@ -755,17 +762,18 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
err = d->remove(d);
if (err == 0) {
- mutex_lock(&drv->core->lock);
list_del(&d->drvlist);
- mutex_unlock(&drv->core->lock);
kfree(d);
} else
printk(KERN_ERR "%s/2: cx8802 driver remove "
"failed (%d)\n", dev->core->name, err);
}
+ mutex_unlock(&dev->core->lock);
}
+ mutex_unlock(&cx8802_mutex);
+
return err;
}
@@ -803,7 +811,9 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
goto fail_free;
INIT_LIST_HEAD(&dev->drvlist);
+ mutex_lock(&cx8802_mutex);
list_add_tail(&dev->devlist,&cx8802_devlist);
+ mutex_unlock(&cx8802_mutex);
/* now autoload cx88-dvb or cx88-blackbird */
request_modules(dev);
@@ -827,6 +837,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
flush_request_modules(dev);
+ mutex_lock(&dev->core->lock);
+
if (!list_empty(&dev->drvlist)) {
struct cx8802_driver *drv, *tmp;
int err;
@@ -838,9 +850,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) {
err = drv->remove(drv);
if (err == 0) {
- mutex_lock(&drv->core->lock);
list_del(&drv->drvlist);
- mutex_unlock(&drv->core->lock);
} else
printk(KERN_ERR "%s/2: cx8802 driver remove "
"failed (%d)\n", dev->core->name, err);
@@ -848,6 +858,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
}
}
+ mutex_unlock(&dev->core->lock);
+
/* Destroy any 8802 reference. */
dev->core->dvbdev = NULL;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 287a41ee1c4f..cef4f282e5aa 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -824,7 +824,7 @@ static int video_open(struct file *file)
call_all(core, tuner, s_radio);
}
- atomic_inc(&core->users);
+ core->users++;
mutex_unlock(&core->lock);
return 0;
@@ -922,7 +922,8 @@ static int video_release(struct file *file)
file->private_data = NULL;
kfree(fh);
- if(atomic_dec_and_test(&dev->core->users))
+ dev->core->users--;
+ if (!dev->core->users)
call_all(dev->core, core, s_power, 0);
mutex_unlock(&dev->core->lock);
@@ -1832,7 +1833,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
dev->core = core;
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", core->name,
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 9b3742a7746c..a399a8b086ba 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -389,8 +389,8 @@ struct cx88_core {
struct mutex lock;
/* various v4l controls */
u32 freq;
- atomic_t users;
- atomic_t mpeg_users;
+ int users;
+ int mpeg_users;
/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
struct cx8802_dev *dvbdev;
@@ -505,6 +505,8 @@ struct cx8802_driver {
int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
int (*resume)(struct pci_dev *pci_dev);
+ /* Callers to the following functions must hold core->lock */
+
/* MPEG 8802 -> mini driver - Driver probe and configuration */
int (*probe)(struct cx8802_driver *drv);
int (*remove)(struct cx8802_driver *drv);
@@ -561,8 +563,9 @@ struct cx8802_dev {
/* for switching modulation types */
unsigned char ts_gen_cntrl;
- /* List of attached drivers */
+ /* List of attached drivers; must hold core->lock to access */
struct list_head drvlist;
+
struct work_struct request_module_wk;
};
@@ -685,6 +688,8 @@ int cx88_audio_thread(void *data);
int cx8802_register_driver(struct cx8802_driver *drv);
int cx8802_unregister_driver(struct cx8802_driver *drv);
+
+/* Caller must hold core->lock */
struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
index 490aafb34e2f..c8b32c1c7386 100644
--- a/drivers/media/video/davinci/dm644x_ccdc.c
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -258,7 +258,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
/*
* Allocate memory for FPC table if current
* FPC table buffer is not big enough to
- * accomodate FPC Number requested
+ * accommodate FPC Number requested
*/
if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
if (fpc_physaddr != NULL) {
@@ -436,7 +436,7 @@ void ccdc_config_ycbcr(void)
/*
* configure the horizontal line offset. This should be a
- * on 32 byte bondary. So clear LSB 5 bits
+ * on 32 byte boundary. So clear LSB 5 bits
*/
regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 71e961e53a56..5b38fc93ff28 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -1691,7 +1691,7 @@ static int vpfe_s_crop(struct file *file, void *priv,
goto unlock_out;
}
- /* adjust the width to 16 pixel boundry */
+ /* adjust the width to 16 pixel boundary */
crop->c.width = ((crop->c.width + 15) & ~0xf);
/* make sure parameters are valid */
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 985100ea17a4..3cb78f26df90 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -38,6 +38,8 @@ config VIDEO_EM28XX_DVB
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_S921 if !DVB_FE_CUSTOMISE
+ select DVB_DRXD if !DVB_FE_CUSTOMISE
+ select DVB_CXD2820R if !DVB_FE_CUSTOMISE
select VIDEOBUF_DVB
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 69fcea82d01c..4e37375decf5 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -100,6 +100,13 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
{ -1, -1, -1, -1},
};
+/* Board Hauppauge WinTV HVR 900 (R2) digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
+ {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x0c, 0x0f, 10},
+ { -1, -1, -1, -1},
+};
+
/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
{EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10},
@@ -282,6 +289,16 @@ static struct em28xx_reg_seq leadership_reset[] = {
{ -1, -1, -1, -1},
};
+/* 2013:024f PCTV Systems nanoStick T2 290e
+ * GPIO_6 - demod reset
+ * GPIO_7 - LED
+ */
+static struct em28xx_reg_seq pctv_290e[] = {
+ {EM2874_R80_GPIO, 0x00, 0xff, 80},
+ {EM2874_R80_GPIO, 0x40, 0xff, 80}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */
+ {-1, -1, -1, -1},
+};
/*
* Board definitions
@@ -859,6 +876,8 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900R2_digital,
.ir_codes = RC_MAP_HAUPPAUGE,
.decoder = EM28XX_TVP5150,
.input = { {
@@ -1448,12 +1467,14 @@ struct em28xx_board em28xx_boards[] = {
.gpio = pinnacle_hybrid_pro_analog,
} },
},
- [EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
- .name = "Pinnacle Hybrid Pro (2)",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
+ [EM2882_BOARD_PINNACLE_HYBRID_PRO_330E] = {
+ .name = "Pinnacle Hybrid Pro (330e)",
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900R2_digital,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1749,6 +1770,17 @@ struct em28xx_board em28xx_boards[] = {
.dvb_gpio = kworld_a340_digital,
.tuner_gpio = default_tuner_gpio,
},
+ /* 2013:024f PCTV Systems nanoStick T2 290e.
+ * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
+ [EM28174_BOARD_PCTV_290E] = {
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .name = "PCTV Systems nanoStick T2 290e",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_290e,
+ .has_dvb = 1,
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1863,7 +1895,7 @@ struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0x2304, 0x021a),
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
{ USB_DEVICE(0x2304, 0x0226),
- .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO },
+ .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E },
{ USB_DEVICE(0x2304, 0x0227),
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
{ USB_DEVICE(0x0413, 0x6023),
@@ -1876,6 +1908,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2860_BOARD_GADMEI_UTV330 },
{ USB_DEVICE(0x1b80, 0xa340),
.driver_info = EM2870_BOARD_KWORLD_A340 },
+ { USB_DEVICE(0x2013, 0x024f),
+ .driver_info = EM28174_BOARD_PCTV_290E },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2229,7 +2263,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_ZARLINK456;
break;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
- /* djh - Not sure which demod we need here */
+ case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
ctl->demod = XC3028_FE_DEFAULT;
break;
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
@@ -2799,6 +2833,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
break;
+ case CHIP_ID_EM28174:
+ em28xx_info("chip ID is em28174\n");
+ dev->reg_gpio_num = EM2874_R80_GPIO;
+ dev->wait_after_write = 0;
+ break;
case CHIP_ID_EM2883:
em28xx_info("chip ID is em2882/em2883\n");
dev->wait_after_write = 0;
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 44c63cbd6dda..e33f145d867a 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -489,7 +489,8 @@ int em28xx_audio_setup(struct em28xx *dev)
int vid1, vid2, feat, cfg;
u32 vid;
- if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) {
+ if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
+ || dev->chip_id == CHIP_ID_EM28174) {
/* Digital only device - don't load any alsa module */
dev->audio_mode.has_audio = 0;
dev->has_audio_class = 0;
@@ -614,7 +615,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
{
int rc;
- if (dev->chip_id == CHIP_ID_EM2874) {
+ if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
/* The Transport Stream Enable Register moved in em2874 */
if (!start) {
rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
@@ -1111,6 +1112,10 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
/* FIXME - for now assume 564 like it was before, but the
em2874 code should be added to return the proper value... */
packet_size = 564;
+ } else if (dev->chip_id == CHIP_ID_EM28174) {
+ /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T
+ but too much for 44 Mbit DVB-C. */
+ packet_size = 752;
} else {
/* TS max packet size stored in bits 1-0 of R01 */
chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index c7c04bf712aa..7904ca4b6913 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -38,6 +38,8 @@
#include "tda1002x.h"
#include "tda18271.h"
#include "s921.h"
+#include "drxd.h"
+#include "cxd2820r.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -58,7 +60,7 @@ if (debug >= level) \
#define EM28XX_DVB_MAX_PACKETS 64
struct em28xx_dvb {
- struct dvb_frontend *frontend;
+ struct dvb_frontend *fe[2];
/* feed count management */
struct mutex lock;
@@ -285,12 +287,13 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
.if2 = 45600,
};
-#ifdef EM28XX_DRX397XD_SUPPORT
-/* [TODO] djh - not sure yet what the device config needs to contain */
-static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
- .demod_address = (0xe0 >> 1),
+static struct drxd_config em28xx_drxd = {
+ .index = 0, .demod_address = 0x70, .demod_revision = 0xa2,
+ .demoda_address = 0x00, .pll_address = 0x00,
+ .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1,
+ .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000,
+ .disable_i2c_gate_ctrl = 1,
};
-#endif
static int mt352_terratec_xs_init(struct dvb_frontend *fe)
{
@@ -332,6 +335,26 @@ static struct tda10023_config em28xx_tda10023_config = {
.invert = 1,
};
+static struct cxd2820r_config em28xx_cxd2820r_config = {
+ .i2c_address = (0xd8 >> 1),
+ .ts_mode = CXD2820R_TS_SERIAL,
+ .if_dvbt_6 = 3300,
+ .if_dvbt_7 = 3500,
+ .if_dvbt_8 = 4000,
+ .if_dvbt2_6 = 3300,
+ .if_dvbt2_7 = 3500,
+ .if_dvbt2_8 = 4000,
+ .if_dvbc = 5000,
+
+ /* enable LNA for DVB-T2 and DVB-C */
+ .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+ .gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+};
+
+static struct tda18271_config em28xx_cxd2820r_tda18271_config = {
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
/* ------------------------------------------------------------------ */
static int attach_xc3028(u8 addr, struct em28xx *dev)
@@ -343,17 +366,17 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
cfg.i2c_adap = &dev->i2c_adap;
cfg.i2c_addr = addr;
- if (!dev->dvb->frontend) {
+ if (!dev->dvb->fe[0]) {
em28xx_errdev("/2: dvb frontend not attached. "
"Can't attach xc3028\n");
return -EINVAL;
}
- fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
+ fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg);
if (!fe) {
em28xx_errdev("/2: xc3028 attach failed\n");
- dvb_frontend_detach(dev->dvb->frontend);
- dev->dvb->frontend = NULL;
+ dvb_frontend_detach(dev->dvb->fe[0]);
+ dev->dvb->fe[0] = NULL;
return -EINVAL;
}
@@ -383,16 +406,28 @@ static int register_dvb(struct em28xx_dvb *dvb,
}
/* Ensure all frontends negotiate bus access */
- dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+ dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+ if (dvb->fe[1])
+ dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
dvb->adapter.priv = dev;
/* register frontend */
- result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
dev->name, result);
- goto fail_frontend;
+ goto fail_frontend0;
+ }
+
+ /* register 2nd frontend */
+ if (dvb->fe[1]) {
+ result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_frontend1;
+ }
}
/* register demux stuff */
@@ -458,9 +493,14 @@ fail_fe_hw:
fail_dmxdev:
dvb_dmx_release(&dvb->demux);
fail_dmx:
- dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
- dvb_frontend_detach(dvb->frontend);
+ if (dvb->fe[1])
+ dvb_unregister_frontend(dvb->fe[1]);
+ dvb_unregister_frontend(dvb->fe[0]);
+fail_frontend1:
+ if (dvb->fe[1])
+ dvb_frontend_detach(dvb->fe[1]);
+fail_frontend0:
+ dvb_frontend_detach(dvb->fe[0]);
dvb_unregister_adapter(&dvb->adapter);
fail_adapter:
return result;
@@ -473,12 +513,15 @@ static void unregister_dvb(struct em28xx_dvb *dvb)
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);
+ if (dvb->fe[1])
+ dvb_unregister_frontend(dvb->fe[1]);
+ dvb_unregister_frontend(dvb->fe[0]);
+ if (dvb->fe[1])
+ dvb_frontend_detach(dvb->fe[1]);
+ dvb_frontend_detach(dvb->fe[0]);
dvb_unregister_adapter(&dvb->adapter);
}
-
static int dvb_init(struct em28xx *dev)
{
int result = 0;
@@ -497,16 +540,17 @@ static int dvb_init(struct em28xx *dev)
return -ENOMEM;
}
dev->dvb = dvb;
+ dvb->fe[0] = dvb->fe[1] = NULL;
mutex_lock(&dev->lock);
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
case EM2874_LEADERSHIP_ISDBT:
- dvb->frontend = dvb_attach(s921_attach,
+ dvb->fe[0] = dvb_attach(s921_attach,
&sharp_isdbt, &dev->i2c_adap);
- if (!dvb->frontend) {
+ if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
}
@@ -516,7 +560,7 @@ static int dvb_init(struct em28xx *dev)
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
- dvb->frontend = dvb_attach(lgdt330x_attach,
+ dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -525,7 +569,7 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2880_BOARD_KWORLD_DVB_310U:
- dvb->frontend = dvb_attach(zl10353_attach,
+ dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_with_xc3028,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -536,7 +580,7 @@ static int dvb_init(struct em28xx *dev)
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
case EM2882_BOARD_TERRATEC_HYBRID_XS:
case EM2880_BOARD_EMPIRE_DUAL_TV:
- dvb->frontend = dvb_attach(zl10353_attach,
+ dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -549,13 +593,13 @@ static int dvb_init(struct em28xx *dev)
case EM2881_BOARD_PINNACLE_HYBRID_PRO:
case EM2882_BOARD_DIKOM_DK300:
case EM2882_BOARD_KWORLD_VS_DVBT:
- dvb->frontend = dvb_attach(zl10353_attach,
+ dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap);
- if (dvb->frontend == NULL) {
+ if (dvb->fe[0] == NULL) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn't for zl10353, try mt352 */
- dvb->frontend = dvb_attach(mt352_attach,
+ dvb->fe[0] = dvb_attach(mt352_attach,
&terratec_xs_mt352_cfg,
&dev->i2c_adap);
}
@@ -567,7 +611,7 @@ static int dvb_init(struct em28xx *dev)
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
- dvb->frontend = dvb_attach(s5h1409_attach,
+ dvb->fe[0] = dvb_attach(s5h1409_attach,
&em28xx_s5h1409_with_xc3028,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -576,11 +620,11 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2882_BOARD_KWORLD_ATSC_315U:
- dvb->frontend = dvb_attach(lgdt330x_attach,
+ dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
&dev->i2c_adap);
- if (dvb->frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+ if (dvb->fe[0] != NULL) {
+ if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
result = -EINVAL;
goto out_free;
@@ -588,25 +632,21 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
-#ifdef EM28XX_DRX397XD_SUPPORT
- /* We don't have the config structure properly populated, so
- this is commented out for now */
- dvb->frontend = dvb_attach(drx397xD_attach,
- &em28xx_drx397xD_with_xc3028,
- &dev->i2c_adap);
+ case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+ dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
+ &dev->i2c_adap, &dev->udev->dev);
if (attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
}
break;
-#endif
case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
- dvb->frontend = dvb_attach(tda10023_attach,
+ dvb->fe[0] = dvb_attach(tda10023_attach,
&em28xx_tda10023_config,
&dev->i2c_adap, 0x48);
- if (dvb->frontend) {
- if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+ if (dvb->fe[0]) {
+ if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
result = -EINVAL;
goto out_free;
@@ -614,25 +654,53 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2870_BOARD_KWORLD_A340:
- dvb->frontend = dvb_attach(lgdt3305_attach,
+ dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev,
&dev->i2c_adap);
- if (dvb->frontend != NULL)
- dvb_attach(tda18271_attach, dvb->frontend, 0x60,
+ if (dvb->fe[0] != NULL)
+ dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap, &kworld_a340_config);
break;
+ case EM28174_BOARD_PCTV_290E:
+ /* MFE
+ * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */
+ /* FE 0 */
+ dvb->fe[0] = dvb_attach(cxd2820r_attach,
+ &em28xx_cxd2820r_config, &dev->i2c_adap, NULL);
+ if (dvb->fe[0]) {
+ struct i2c_adapter *i2c_tuner;
+ i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]);
+ /* FE 0 attach tuner */
+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -EINVAL;
+ goto out_free;
+ }
+ /* FE 1. This dvb_attach() cannot fail. */
+ dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL,
+ dvb->fe[0]);
+ dvb->fe[1]->id = 1;
+ /* FE 1 attach tuner */
+ if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60,
+ i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+ dvb_frontend_detach(dvb->fe[1]);
+ /* leave FE 0 still active */
+ }
+ }
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
break;
}
- if (NULL == dvb->frontend) {
+ if (NULL == dvb->fe[0]) {
em28xx_errdev("/2: frontend initialization failed\n");
result = -EINVAL;
goto out_free;
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = em28xx_tuner_callback;
+ dvb->fe[0]->callback = em28xx_tuner_callback;
/* register everything */
result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 71474d31e155..4739fc7e6eb3 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -332,7 +332,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
struct em28xx_eeprom *em_eeprom = (void *)eedata;
int i, err, size = len, block;
- if (dev->chip_id == CHIP_ID_EM2874) {
+ if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
/* Empia switched to a 16-bit addressable eeprom in newer
devices. While we could certainly write a routine to read
the eeprom, there is nothing of use in there that cannot be
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 91e90559642b..e92a28ede434 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -201,6 +201,7 @@ enum em28xx_chip_id {
CHIP_ID_EM2870 = 35,
CHIP_ID_EM2883 = 36,
CHIP_ID_EM2874 = 65,
+ CHIP_ID_EM28174 = 113,
};
/*
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index a83131bd00b2..7b6461d2d1ff 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -377,7 +377,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
/* Get the next buffer */
*buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
- /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
outp = videobuf_to_vmalloc(&(*buf)->vb);
memset(outp, 0, (*buf)->vb.size);
@@ -404,7 +404,7 @@ static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
/* Get the next buffer */
*buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
- /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
outp = videobuf_to_vmalloc(&(*buf)->vb);
memset(outp, 0x00, (*buf)->vb.size);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 6f2795a3d4b7..3cca33122450 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -97,7 +97,7 @@
#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53
#define EM2882_BOARD_KWORLD_VS_DVBT 54
#define EM2882_BOARD_TERRATEC_HYBRID_XS 55
-#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56
+#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56
#define EM2883_BOARD_KWORLD_HYBRID_330U 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
@@ -118,6 +118,7 @@
#define EM2882_BOARD_DIKOM_DK300 75
#define EM2870_BOARD_KWORLD_A340 76
#define EM2874_LEADERSHIP_ISDBT 77
+#define EM28174_BOARD_PCTV_290E 78
/* Limits minimum and default number of buffers */
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
index 031af1610154..908d7012c3f2 100644
--- a/drivers/media/video/fsl-viu.c
+++ b/drivers/media/video/fsl-viu.c
@@ -766,7 +766,7 @@ inline void viu_activate_overlay(struct viu_reg *viu_reg)
out_be32(&vr->picture_count, reg_val.picture_count);
}
-static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
+static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh)
{
int bpp;
@@ -805,11 +805,6 @@ static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
/* setup the base address of the overlay buffer */
reg_val.field_base_addr = (u32)dev->ovbuf.base;
- dev->ovenable = 1;
- viu_activate_overlay(dev->vr);
-
- /* start dma */
- viu_start_dma(dev);
return 0;
}
@@ -825,13 +820,11 @@ static int vidioc_s_fmt_overlay(struct file *file, void *priv,
if (err)
return err;
- mutex_lock(&dev->lock);
fh->win = f->fmt.win;
spin_lock_irqsave(&dev->slock, flags);
- viu_start_preview(dev, fh);
+ viu_setup_preview(dev, fh);
spin_unlock_irqrestore(&dev->slock, flags);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -841,6 +834,28 @@ static int vidioc_try_fmt_overlay(struct file *file, void *priv,
return 0;
}
+static int vidioc_overlay(struct file *file, void *priv, unsigned int on)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+ unsigned long flags;
+
+ if (on) {
+ spin_lock_irqsave(&dev->slock, flags);
+ viu_activate_overlay(dev->vr);
+ dev->ovenable = 1;
+
+ /* start dma */
+ viu_start_dma(dev);
+ spin_unlock_irqrestore(&dev->slock, flags);
+ } else {
+ viu_stop_dma(dev);
+ dev->ovenable = 0;
+ }
+
+ return 0;
+}
+
int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
{
struct viu_fh *fh = priv;
@@ -911,12 +926,16 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (fh->type != i)
return -EINVAL;
+ if (dev->ovenable)
+ dev->ovenable = 0;
+
viu_start_dma(fh->dev);
return videobuf_streamon(&fh->vb_vidq);
@@ -1311,7 +1330,8 @@ static int viu_open(struct file *file)
videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
dev->dev, &fh->vbq_lock,
fh->type, V4L2_FIELD_INTERLACED,
- sizeof(struct viu_buf), fh, NULL);
+ sizeof(struct viu_buf), fh,
+ &fh->dev->lock);
return 0;
}
@@ -1401,7 +1421,7 @@ static struct v4l2_file_operations viu_fops = {
.release = viu_release,
.read = viu_read,
.poll = viu_poll,
- .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = viu_mmap,
};
@@ -1415,6 +1435,7 @@ static const struct v4l2_ioctl_ops viu_ioctl_ops = {
.vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+ .vidioc_overlay = vidioc_overlay,
.vidioc_g_fbuf = vidioc_g_fbuf,
.vidioc_s_fbuf = vidioc_s_fbuf,
.vidioc_reqbufs = vidioc_reqbufs,
@@ -1498,9 +1519,6 @@ static int __devinit viu_of_probe(struct platform_device *op)
INIT_LIST_HEAD(&viu_dev->vidq.active);
INIT_LIST_HEAD(&viu_dev->vidq.queued);
- /* initialize locks */
- mutex_init(&viu_dev->lock);
-
snprintf(viu_dev->v4l2_dev.name,
sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
@@ -1531,8 +1549,15 @@ static int __devinit viu_of_probe(struct platform_device *op)
viu_dev->vdev = vdev;
+ /* initialize locks */
+ mutex_init(&viu_dev->lock);
+ viu_dev->vdev->lock = &viu_dev->lock;
+ spin_lock_init(&viu_dev->slock);
+
video_set_drvdata(viu_dev->vdev, viu_dev);
+ mutex_lock(&viu_dev->lock);
+
ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
video_device_release(viu_dev->vdev);
@@ -1559,6 +1584,8 @@ static int __devinit viu_of_probe(struct platform_device *op)
goto err_irq;
}
+ mutex_unlock(&viu_dev->lock);
+
dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
return ret;
@@ -1568,6 +1595,7 @@ err_irq:
err_clk:
video_unregister_device(viu_dev->vdev);
err_vdev:
+ mutex_unlock(&viu_dev->lock);
i2c_put_adapter(ad);
v4l2_device_unregister(&viu_dev->v4l2_dev);
err:
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index eb04e8b59989..34ae2c299799 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -77,6 +77,15 @@ config USB_GSPCA_JEILINJ
To compile this driver as a module, choose M here: the
module will be called gspca_jeilinj.
+config USB_GSPCA_KINECT
+ tristate "Kinect sensor device USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for the Microsoft Kinect sensor device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_kinect.
+
config USB_GSPCA_KONICA
tristate "Konica USB Camera V4L2 driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 855fbc8c9c47..802fbe1bff4a 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o
obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o
obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
@@ -46,6 +47,7 @@ gspca_cpia1-objs := cpia1.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
+gspca_kinect-objs := kinect.o
gspca_konica-objs := konica.o
gspca_mars-objs := mars.o
gspca_mr97310a-objs := mr97310a.o
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index 9ddbac680663..f2a9451eea19 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -1262,7 +1262,7 @@ static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
static void monitor_exposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 exp_acc, bcomp, gain, coarseL, cmd[8];
+ u8 exp_acc, bcomp, cmd[8];
int ret, light_exp, dark_exp, very_dark_exp;
int old_exposure, new_exposure, framerate;
int setfps = 0, setexp = 0, setflicker = 0;
@@ -1284,8 +1284,6 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
}
exp_acc = gspca_dev->usb_buf[0];
bcomp = gspca_dev->usb_buf[1];
- gain = gspca_dev->usb_buf[2];
- coarseL = gspca_dev->usb_buf[3];
light_exp = sd->params.colourParams.brightness +
TC - 50 + EXP_ACC_LIGHT;
@@ -1772,9 +1770,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
-#ifdef GSPCA_DEBUG
struct sd *sd = (struct sd *) gspca_dev;
-#endif
int ret;
/* Start / Stop the camera to make sure we are talking to
diff --git a/drivers/media/video/gspca/gl860/gl860-mi1320.c b/drivers/media/video/gspca/gl860/gl860-mi1320.c
index c276a7debdec..b57160e04866 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi1320.c
+++ b/drivers/media/video/gspca/gl860/gl860-mi1320.c
@@ -201,7 +201,7 @@ void mi1320_init_settings(struct gspca_dev *gspca_dev)
sd->vmax.backlight = 2;
sd->vmax.brightness = 8;
sd->vmax.sharpness = 7;
- sd->vmax.contrast = 0; /* 10 but not working with tihs driver */
+ sd->vmax.contrast = 0; /* 10 but not working with this driver */
sd->vmax.gamma = 40;
sd->vmax.hue = 5 + 1;
sd->vmax.saturation = 8;
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index 99083038cec3..e8e071aa212f 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -499,21 +499,8 @@ MODULE_DEVICE_TABLE(usb, device_table);
static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct gspca_dev *gspca_dev;
- s32 ret;
-
- ret = gspca_dev_probe(intf, id,
+ return gspca_dev_probe(intf, id,
&sd_desc_mi1320, sizeof(struct sd), THIS_MODULE);
-
- if (ret >= 0) {
- gspca_dev = usb_get_intfdata(intf);
-
- PDEBUG(D_PROBE,
- "Camera is now controlling video device %s",
- video_device_node_name(&gspca_dev->vdev));
- }
-
- return ret;
}
static void sd_disconnect(struct usb_interface *intf)
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 9c6a643caf01..08ce9948d99b 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 13, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -857,7 +857,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
}
/* the bandwidth is not wide enough
- * negociate or try a lower alternate setting */
+ * negotiate or try a lower alternate setting */
PDEBUG(D_ERR|D_STREAM,
"bandwidth not wide enough - trying again");
msleep(20); /* wait for kill complete */
@@ -2346,7 +2346,7 @@ void gspca_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
/* release the device */
- /* (this will call gspca_release() immediatly or on last close) */
+ /* (this will call gspca_release() immediately or on last close) */
video_unregister_device(&gspca_dev->vdev);
/* PDEBUG(D_PROBE, "disconnect complete"); */
@@ -2495,6 +2495,6 @@ module_exit(gspca_exit);
module_param_named(debug, gspca_debug, int, 0644);
MODULE_PARM_DESC(debug,
"Debug (bit) 0x01:error 0x02:probe 0x04:config"
- " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
+ " 0x08:stream 0x10:frame 0x20:packet"
" 0x0100: v4l2");
#endif
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 41755226d389..49e2fcbe81fb 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -9,7 +9,7 @@
#include <linux/mutex.h>
/* compilation option */
-#define GSPCA_DEBUG 1
+/*#define GSPCA_DEBUG 1*/
#ifdef GSPCA_DEBUG
/* GSPCA our debug messages */
@@ -25,8 +25,8 @@ extern int gspca_debug;
#define D_STREAM 0x08
#define D_FRAM 0x10
#define D_PACK 0x20
-#define D_USBI 0x40
-#define D_USBO 0x80
+#define D_USBI 0x00
+#define D_USBO 0x00
#define D_V4L2 0x0100
#else
#define PDEBUG(level, fmt, args...)
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index 36dae38b1e38..1bd9c4b542dd 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -6,6 +6,9 @@
*
* Copyright (C) 2009 Theodore Kilgore
*
+ * Sportscam DV15 support and control settings are
+ * Copyright (C) 2011 Patrice Chotard
+ *
* 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
@@ -23,7 +26,6 @@
#define MODULE_NAME "jeilinj"
-#include <linux/workqueue.h>
#include <linux/slab.h>
#include "gspca.h"
#include "jpeg.h"
@@ -34,29 +36,51 @@ MODULE_LICENSE("GPL");
/* Default timeouts, in ms */
#define JEILINJ_CMD_TIMEOUT 500
+#define JEILINJ_CMD_DELAY 160
#define JEILINJ_DATA_TIMEOUT 1000
/* Maximum transfer size to use. */
#define JEILINJ_MAX_TRANSFER 0x200
-
#define FRAME_HEADER_LEN 0x10
+#define FRAME_START 0xFFFFFFFF
+
+enum {
+ SAKAR_57379,
+ SPORTSCAM_DV15,
+};
+
+#define CAMQUALITY_MIN 0 /* highest cam quality */
+#define CAMQUALITY_MAX 97 /* lowest cam quality */
+
+enum e_ctrl {
+ LIGHTFREQ,
+ AUTOGAIN,
+ RED,
+ GREEN,
+ BLUE,
+ NCTRLS /* number of controls */
+};
/* Structure to hold all of our device specific stuff */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
+ struct gspca_ctrl ctrls[NCTRLS];
+ int blocks_left;
const struct v4l2_pix_format *cap_mode;
/* Driver stuff */
- struct work_struct work_struct;
- struct workqueue_struct *work_thread;
+ u8 type;
u8 quality; /* image quality */
- u8 jpegqual; /* webcam quality */
+#define QUALITY_MIN 35
+#define QUALITY_MAX 85
+#define QUALITY_DEF 85
u8 jpeg_hdr[JPEG_HDR_SZ];
};
- struct jlj_command {
- unsigned char instruction[2];
- unsigned char ack_wanted;
- };
+struct jlj_command {
+ unsigned char instruction[2];
+ unsigned char ack_wanted;
+ unsigned char delay;
+};
/* AFAICT these cameras will only do 320x240. */
static struct v4l2_pix_format jlj_mode[] = {
@@ -64,6 +88,11 @@ static struct v4l2_pix_format jlj_mode[] = {
.bytesperline = 320,
.sizeimage = 320 * 240,
.colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+ { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0}
};
@@ -73,178 +102,295 @@ static struct v4l2_pix_format jlj_mode[] = {
*/
/* All commands are two bytes only */
-static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
{
int retval;
+ if (gspca_dev->usb_err < 0)
+ return;
memcpy(gspca_dev->usb_buf, command, 2);
retval = usb_bulk_msg(gspca_dev->dev,
usb_sndbulkpipe(gspca_dev->dev, 3),
gspca_dev->usb_buf, 2, NULL, 500);
- if (retval < 0)
+ if (retval < 0) {
err("command write [%02x] error %d",
gspca_dev->usb_buf[0], retval);
- return retval;
+ gspca_dev->usb_err = retval;
+ }
}
/* Responses are one byte only */
-static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
+static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
{
int retval;
+ if (gspca_dev->usb_err < 0)
+ return;
retval = usb_bulk_msg(gspca_dev->dev,
usb_rcvbulkpipe(gspca_dev->dev, 0x84),
gspca_dev->usb_buf, 1, NULL, 500);
response = gspca_dev->usb_buf[0];
- if (retval < 0)
+ if (retval < 0) {
err("read command [%02x] error %d",
gspca_dev->usb_buf[0], retval);
- return retval;
+ gspca_dev->usb_err = retval;
+ }
}
-static int jlj_start(struct gspca_dev *gspca_dev)
+static void setfreq(struct gspca_dev *gspca_dev)
{
- int i;
- int retval = -1;
- u8 response = 0xff;
- struct jlj_command start_commands[] = {
- {{0x71, 0x81}, 0},
- {{0x70, 0x05}, 0},
- {{0x95, 0x70}, 1},
- {{0x71, 0x81}, 0},
- {{0x70, 0x04}, 0},
- {{0x95, 0x70}, 1},
- {{0x71, 0x00}, 0},
- {{0x70, 0x08}, 0},
- {{0x95, 0x70}, 1},
- {{0x94, 0x02}, 0},
- {{0xde, 0x24}, 0},
- {{0x94, 0x02}, 0},
- {{0xdd, 0xf0}, 0},
- {{0x94, 0x02}, 0},
- {{0xe3, 0x2c}, 0},
- {{0x94, 0x02}, 0},
- {{0xe4, 0x00}, 0},
- {{0x94, 0x02}, 0},
- {{0xe5, 0x00}, 0},
- {{0x94, 0x02}, 0},
- {{0xe6, 0x2c}, 0},
- {{0x94, 0x03}, 0},
- {{0xaa, 0x00}, 0},
- {{0x71, 0x1e}, 0},
- {{0x70, 0x06}, 0},
- {{0x71, 0x80}, 0},
- {{0x70, 0x07}, 0}
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 freq_commands[][2] = {
+ {0x71, 0x80},
+ {0x70, 0x07}
};
- for (i = 0; i < ARRAY_SIZE(start_commands); i++) {
- retval = jlj_write2(gspca_dev, start_commands[i].instruction);
- if (retval < 0)
- return retval;
- if (start_commands[i].ack_wanted)
- retval = jlj_read1(gspca_dev, response);
- if (retval < 0)
- return retval;
- }
- PDEBUG(D_ERR, "jlj_start retval is %d", retval);
- return retval;
+
+ freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1);
+
+ jlj_write2(gspca_dev, freq_commands[0]);
+ jlj_write2(gspca_dev, freq_commands[1]);
}
-static int jlj_stop(struct gspca_dev *gspca_dev)
+static void setcamquality(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 quality_commands[][2] = {
+ {0x71, 0x1E},
+ {0x70, 0x06}
+ };
+ u8 camquality;
+
+ /* adapt camera quality from jpeg quality */
+ camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX)
+ / (QUALITY_MAX - QUALITY_MIN);
+ quality_commands[0][1] += camquality;
+
+ jlj_write2(gspca_dev, quality_commands[0]);
+ jlj_write2(gspca_dev, quality_commands[1]);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 autogain_commands[][2] = {
+ {0x94, 0x02},
+ {0xcf, 0x00}
+ };
+
+ autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4);
+
+ jlj_write2(gspca_dev, autogain_commands[0]);
+ jlj_write2(gspca_dev, autogain_commands[1]);
+}
+
+static void setred(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 setred_commands[][2] = {
+ {0x94, 0x02},
+ {0xe6, 0x00}
+ };
+
+ setred_commands[1][1] = sd->ctrls[RED].val;
+
+ jlj_write2(gspca_dev, setred_commands[0]);
+ jlj_write2(gspca_dev, setred_commands[1]);
+}
+
+static void setgreen(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 setgreen_commands[][2] = {
+ {0x94, 0x02},
+ {0xe7, 0x00}
+ };
+
+ setgreen_commands[1][1] = sd->ctrls[GREEN].val;
+
+ jlj_write2(gspca_dev, setgreen_commands[0]);
+ jlj_write2(gspca_dev, setgreen_commands[1]);
+}
+
+static void setblue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 setblue_commands[][2] = {
+ {0x94, 0x02},
+ {0xe9, 0x00}
+ };
+
+ setblue_commands[1][1] = sd->ctrls[BLUE].val;
+
+ jlj_write2(gspca_dev, setblue_commands[0]);
+ jlj_write2(gspca_dev, setblue_commands[1]);
+}
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[LIGHTFREQ] = {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */
+ .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */
+ .step = 1,
+ .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ },
+ .set_control = setfreq
+ },
+[AUTOGAIN] = {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Automatic Gain (and Exposure)",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define AUTOGAIN_DEF 0
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set_control = setautogain
+ },
+[RED] = {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define RED_BALANCE_DEF 2
+ .default_value = RED_BALANCE_DEF,
+ },
+ .set_control = setred
+ },
+
+[GREEN] = {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define GREEN_BALANCE_DEF 2
+ .default_value = GREEN_BALANCE_DEF,
+ },
+ .set_control = setgreen
+ },
+[BLUE] = {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define BLUE_BALANCE_DEF 2
+ .default_value = BLUE_BALANCE_DEF,
+ },
+ .set_control = setblue
+ },
+};
+
+static int jlj_start(struct gspca_dev *gspca_dev)
{
int i;
- int retval;
- struct jlj_command stop_commands[] = {
- {{0x71, 0x00}, 0},
- {{0x70, 0x09}, 0},
- {{0x71, 0x80}, 0},
- {{0x70, 0x05}, 0}
+ int start_commands_size;
+ u8 response = 0xff;
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct jlj_command start_commands[] = {
+ {{0x71, 0x81}, 0, 0},
+ {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY},
+ {{0x95, 0x70}, 1, 0},
+ {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0},
+ {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY},
+ {{0x95, 0x70}, 1, 0},
+ {{0x71, 0x00}, 0, 0}, /* start streaming ??*/
+ {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY},
+ {{0x95, 0x70}, 1, 0},
+#define SPORTSCAM_DV15_CMD_SIZE 9
+ {{0x94, 0x02}, 0, 0},
+ {{0xde, 0x24}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xdd, 0xf0}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe3, 0x2c}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe4, 0x00}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe5, 0x00}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe6, 0x2c}, 0, 0},
+ {{0x94, 0x03}, 0, 0},
+ {{0xaa, 0x00}, 0, 0}
};
- for (i = 0; i < ARRAY_SIZE(stop_commands); i++) {
- retval = jlj_write2(gspca_dev, stop_commands[i].instruction);
- if (retval < 0)
- return retval;
+
+ sd->blocks_left = 0;
+ /* Under Windows, USB spy shows that only the 9 first start
+ * commands are used for SPORTSCAM_DV15 webcam
+ */
+ if (sd->type == SPORTSCAM_DV15)
+ start_commands_size = SPORTSCAM_DV15_CMD_SIZE;
+ else
+ start_commands_size = ARRAY_SIZE(start_commands);
+
+ for (i = 0; i < start_commands_size; i++) {
+ jlj_write2(gspca_dev, start_commands[i].instruction);
+ if (start_commands[i].delay)
+ msleep(start_commands[i].delay);
+ if (start_commands[i].ack_wanted)
+ jlj_read1(gspca_dev, response);
}
- return retval;
+ setcamquality(gspca_dev);
+ msleep(2);
+ setfreq(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ PDEBUG(D_ERR, "Start streaming command failed");
+ return gspca_dev->usb_err;
}
-/* This function is called as a workqueue function and runs whenever the camera
- * is streaming data. Because it is a workqueue function it is allowed to sleep
- * so we can use synchronous USB calls. To avoid possible collisions with other
- * threads attempting to use the camera's USB interface the gspca usb_lock is
- * used when performing the one USB control operation inside the workqueue,
- * which tells the camera to close the stream. In practice the only thing
- * which needs to be protected against is the usb_set_interface call that
- * gspca makes during stream_off. Otherwise the camera doesn't provide any
- * controls that the user could try to change.
- */
-
-static void jlj_dostream(struct work_struct *work)
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, int len)
{
- struct sd *dev = container_of(work, struct sd, work_struct);
- struct gspca_dev *gspca_dev = &dev->gspca_dev;
- int blocks_left; /* 0x200-sized blocks remaining in current frame. */
- int act_len;
+ struct sd *sd = (struct sd *) gspca_dev;
int packet_type;
- int ret;
- u8 *buffer;
+ u32 header_marker;
- buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
- if (!buffer) {
- err("Couldn't allocate USB buffer");
- goto quit_stream;
+ PDEBUG(D_STREAM, "Got %d bytes out of %d for Block 0",
+ len, JEILINJ_MAX_TRANSFER);
+ if (len != JEILINJ_MAX_TRANSFER) {
+ PDEBUG(D_PACK, "bad length");
+ goto discard;
}
- while (gspca_dev->present && gspca_dev->streaming) {
- /*
- * Now request data block 0. Line 0 reports the size
- * to download, in blocks of size 0x200, and also tells the
- * "actual" data size, in bytes, which seems best to ignore.
- */
- ret = usb_bulk_msg(gspca_dev->dev,
- usb_rcvbulkpipe(gspca_dev->dev, 0x82),
- buffer, JEILINJ_MAX_TRANSFER, &act_len,
- JEILINJ_DATA_TIMEOUT);
- PDEBUG(D_STREAM,
- "Got %d bytes out of %d for Block 0",
- act_len, JEILINJ_MAX_TRANSFER);
- if (ret < 0 || act_len < FRAME_HEADER_LEN)
- goto quit_stream;
- blocks_left = buffer[0x0a] - 1;
- PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
-
+ /* check if it's start of frame */
+ header_marker = ((u32 *)data)[0];
+ if (header_marker == FRAME_START) {
+ sd->blocks_left = data[0x0a] - 1;
+ PDEBUG(D_STREAM, "blocks_left = 0x%x", sd->blocks_left);
/* Start a new frame, and add the JPEG header, first thing */
gspca_frame_add(gspca_dev, FIRST_PACKET,
- dev->jpeg_hdr, JPEG_HDR_SZ);
+ sd->jpeg_hdr, JPEG_HDR_SZ);
/* Toss line 0 of data block 0, keep the rest. */
gspca_frame_add(gspca_dev, INTER_PACKET,
- buffer + FRAME_HEADER_LEN,
+ data + FRAME_HEADER_LEN,
JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
-
- while (blocks_left > 0) {
- if (!gspca_dev->present)
- goto quit_stream;
- ret = usb_bulk_msg(gspca_dev->dev,
- usb_rcvbulkpipe(gspca_dev->dev, 0x82),
- buffer, JEILINJ_MAX_TRANSFER, &act_len,
- JEILINJ_DATA_TIMEOUT);
- if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER)
- goto quit_stream;
- PDEBUG(D_STREAM,
- "%d blocks remaining for frame", blocks_left);
- blocks_left -= 1;
- if (blocks_left == 0)
- packet_type = LAST_PACKET;
- else
- packet_type = INTER_PACKET;
- gspca_frame_add(gspca_dev, packet_type,
- buffer, JEILINJ_MAX_TRANSFER);
- }
- }
-quit_stream:
- mutex_lock(&gspca_dev->usb_lock);
- if (gspca_dev->present)
- jlj_stop(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
- kfree(buffer);
+ } else if (sd->blocks_left > 0) {
+ PDEBUG(D_STREAM, "%d blocks remaining for frame",
+ sd->blocks_left);
+ sd->blocks_left -= 1;
+ if (sd->blocks_left == 0)
+ packet_type = LAST_PACKET;
+ else
+ packet_type = INTER_PACKET;
+ gspca_frame_add(gspca_dev, packet_type,
+ data, JEILINJ_MAX_TRANSFER);
+ } else
+ goto discard;
+ return;
+discard:
+ /* Discard data until a new frame starts. */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
}
/* This function is called at probe time just before sd_init */
@@ -254,78 +400,169 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam = &gspca_dev->cam;
struct sd *dev = (struct sd *) gspca_dev;
- dev->quality = 85;
- dev->jpegqual = 85;
+ dev->type = id->driver_info;
+ gspca_dev->cam.ctrls = dev->ctrls;
+ dev->quality = QUALITY_DEF;
+ dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
+ dev->ctrls[RED].def = RED_BALANCE_DEF;
+ dev->ctrls[GREEN].def = GREEN_BALANCE_DEF;
+ dev->ctrls[BLUE].def = BLUE_BALANCE_DEF;
PDEBUG(D_PROBE,
"JEILINJ camera detected"
" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
cam->cam_mode = jlj_mode;
- cam->nmodes = 1;
+ cam->nmodes = ARRAY_SIZE(jlj_mode);
cam->bulk = 1;
- /* We don't use the buffer gspca allocates so make it small. */
- cam->bulk_size = 32;
- INIT_WORK(&dev->work_struct, jlj_dostream);
+ cam->bulk_nurbs = 1;
+ cam->bulk_size = JEILINJ_MAX_TRANSFER;
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)
+static void sd_stopN(struct gspca_dev *gspca_dev)
{
- struct sd *dev = (struct sd *) gspca_dev;
+ int i;
+ u8 *buf;
+ u8 stop_commands[][2] = {
+ {0x71, 0x00},
+ {0x70, 0x09},
+ {0x71, 0x80},
+ {0x70, 0x05}
+ };
+
+ for (;;) {
+ /* get the image remaining blocks */
+ usb_bulk_msg(gspca_dev->dev,
+ gspca_dev->urb[0]->pipe,
+ gspca_dev->urb[0]->transfer_buffer,
+ JEILINJ_MAX_TRANSFER, NULL,
+ JEILINJ_DATA_TIMEOUT);
+
+ /* search for 0xff 0xd9 (EOF for JPEG) */
+ i = 0;
+ buf = gspca_dev->urb[0]->transfer_buffer;
+ while ((i < (JEILINJ_MAX_TRANSFER - 1)) &&
+ ((buf[i] != 0xff) || (buf[i+1] != 0xd9)))
+ i++;
- /* wait for the work queue to terminate */
- mutex_unlock(&gspca_dev->usb_lock);
- /* This waits for jlj_dostream to finish */
- destroy_workqueue(dev->work_thread);
- dev->work_thread = NULL;
- mutex_lock(&gspca_dev->usb_lock);
+ if (i != (JEILINJ_MAX_TRANSFER - 1))
+ /* last remaining block found */
+ break;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(stop_commands); i++)
+ jlj_write2(gspca_dev, stop_commands[i]);
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- return 0;
+ return gspca_dev->usb_err;
}
/* Set up for getting frames. */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *dev = (struct sd *) gspca_dev;
- int ret;
/* create the JPEG header */
jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(dev->jpeg_hdr, dev->quality);
- PDEBUG(D_STREAM, "Start streaming at 320x240");
- ret = jlj_start(gspca_dev);
- if (ret < 0) {
- PDEBUG(D_ERR, "Start streaming command failed");
- return ret;
- }
- /* Start the workqueue function to do the streaming */
- dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
- queue_work(dev->work_thread, &dev->work_struct);
-
- return 0;
+ PDEBUG(D_STREAM, "Start streaming at %dx%d",
+ gspca_dev->height, gspca_dev->width);
+ jlj_start(gspca_dev);
+ return gspca_dev->usb_err;
}
/* Table of supported USB devices */
static const struct usb_device_id device_table[] = {
- {USB_DEVICE(0x0979, 0x0280)},
+ {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379},
+ {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "disable");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+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);
+ setcamquality(gspca_dev);
+ }
+ 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 = {
+static const struct sd_desc sd_desc_sakar_57379 = {
.name = MODULE_NAME,
.config = sd_config,
.init = sd_init,
.start = sd_start,
- .stop0 = sd_stop0,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* sub-driver description */
+static const struct sd_desc sd_desc_sportscam_dv15 = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .querymenu = sd_querymenu,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
+};
+
+static const struct sd_desc *sd_desc[2] = {
+ &sd_desc_sakar_57379,
+ &sd_desc_sportscam_dv15
};
/* -- device connect -- */
@@ -333,7 +570,7 @@ static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id,
- &sd_desc,
+ sd_desc[id->driver_info],
sizeof(struct sd),
THIS_MODULE);
}
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c
new file mode 100644
index 000000000000..66671a4092e4
--- /dev/null
+++ b/drivers/media/video/gspca/kinect.c
@@ -0,0 +1,429 @@
+/*
+ * kinect sensor device camera, gspca driver
+ *
+ * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * Based on the OpenKinect project and libfreenect
+ * http://openkinect.org/wiki/Init_Analysis
+ *
+ * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect
+ * sensor device which I tested the driver on.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "kinect"
+
+#include "gspca.h"
+
+#define CTRL_TIMEOUT 500
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG
+int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK |
+ D_USBI | D_USBO | D_V4L2;
+#endif
+
+struct pkt_hdr {
+ uint8_t magic[2];
+ uint8_t pad;
+ uint8_t flag;
+ uint8_t unk1;
+ uint8_t seq;
+ uint8_t unk2;
+ uint8_t unk3;
+ uint32_t timestamp;
+};
+
+struct cam_hdr {
+ uint8_t magic[2];
+ uint16_t len;
+ uint16_t cmd;
+ uint16_t tag;
+};
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ uint16_t cam_tag; /* a sequence number for packets */
+ uint8_t stream_flag; /* to identify different stream types */
+ uint8_t obuf[0x400]; /* output buffer for control commands */
+ uint8_t ibuf[0x200]; /* input buffer for control commands */
+};
+
+/* V4L2 controls supported by the driver */
+/* controls prototypes here */
+
+static const struct ctrl sd_ctrls[] = {
+};
+
+#define MODE_640x480 0x0001
+#define MODE_640x488 0x0002
+#define MODE_1280x1024 0x0004
+
+#define FORMAT_BAYER 0x0010
+#define FORMAT_UYVY 0x0020
+#define FORMAT_Y10B 0x0040
+
+#define FPS_HIGH 0x0100
+
+static const struct v4l2_pix_format video_camera_mode[] = {
+ {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH},
+ {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_640x480 | FORMAT_UYVY},
+ {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_1280x1024 | FORMAT_BAYER},
+ {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 10 / 8,
+ .sizeimage = 640 * 488 * 10 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH},
+ {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE,
+ .bytesperline = 1280 * 10 / 8,
+ .sizeimage = 1280 * 1024 * 10 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_1280x1024 | FORMAT_Y10B},
+};
+
+static int kinect_write(struct usb_device *udev, uint8_t *data,
+ uint16_t wLength)
+{
+ return usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ 0x00,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, data, wLength, CTRL_TIMEOUT);
+}
+
+static int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength)
+{
+ return usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, data, wLength, CTRL_TIMEOUT);
+}
+
+static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
+ unsigned int cmd_len, void *replybuf, unsigned int reply_len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *udev = gspca_dev->dev;
+ int res, actual_len;
+ uint8_t *obuf = sd->obuf;
+ uint8_t *ibuf = sd->ibuf;
+ struct cam_hdr *chdr = (void *)obuf;
+ struct cam_hdr *rhdr = (void *)ibuf;
+
+ if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) {
+ err("send_cmd: Invalid command length (0x%x)", cmd_len);
+ return -1;
+ }
+
+ chdr->magic[0] = 0x47;
+ chdr->magic[1] = 0x4d;
+ chdr->cmd = cpu_to_le16(cmd);
+ chdr->tag = cpu_to_le16(sd->cam_tag);
+ chdr->len = cpu_to_le16(cmd_len / 2);
+
+ memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len);
+
+ res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr));
+ PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd,
+ sd->cam_tag, cmd_len, res);
+ if (res < 0) {
+ err("send_cmd: Output control transfer failed (%d)", res);
+ return res;
+ }
+
+ do {
+ actual_len = kinect_read(udev, ibuf, 0x200);
+ } while (actual_len == 0);
+ PDEBUG(D_USBO, "Control reply: %d", res);
+ if (actual_len < sizeof(*rhdr)) {
+ err("send_cmd: Input control transfer failed (%d)", res);
+ return res;
+ }
+ actual_len -= sizeof(*rhdr);
+
+ if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) {
+ err("send_cmd: Bad magic %02x %02x", rhdr->magic[0],
+ rhdr->magic[1]);
+ return -1;
+ }
+ if (rhdr->cmd != chdr->cmd) {
+ err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd);
+ return -1;
+ }
+ if (rhdr->tag != chdr->tag) {
+ err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag);
+ return -1;
+ }
+ if (cpu_to_le16(rhdr->len) != (actual_len/2)) {
+ err("send_cmd: Bad len %04x != %04x",
+ cpu_to_le16(rhdr->len), (int)(actual_len/2));
+ return -1;
+ }
+
+ if (actual_len > reply_len) {
+ warn("send_cmd: Data buffer is %d bytes long, but got %d bytes",
+ reply_len, actual_len);
+ memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len);
+ } else {
+ memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len);
+ }
+
+ sd->cam_tag++;
+
+ return actual_len;
+}
+
+static int write_register(struct gspca_dev *gspca_dev, uint16_t reg,
+ uint16_t data)
+{
+ uint16_t reply[2];
+ uint16_t cmd[2];
+ int res;
+
+ cmd[0] = cpu_to_le16(reg);
+ cmd[1] = cpu_to_le16(data);
+
+ PDEBUG(D_USBO, "Write Reg 0x%04x <= 0x%02x", reg, data);
+ res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4);
+ if (res < 0)
+ return res;
+ if (res != 2) {
+ warn("send_cmd returned %d [%04x %04x], 0000 expected",
+ res, reply[0], reply[1]);
+ }
+ return 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->cam_tag = 0;
+
+ /* Only video stream is supported for now,
+ * which has stream flag = 0x80 */
+ sd->stream_flag = 0x80;
+
+ cam = &gspca_dev->cam;
+
+ cam->cam_mode = video_camera_mode;
+ cam->nmodes = ARRAY_SIZE(video_camera_mode);
+
+#if 0
+ /* Setting those values is not needed for video stream */
+ cam->npkt = 15;
+ gspca_dev->pkt_size = 960 * 2;
+#endif
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ PDEBUG(D_PROBE, "Kinect Camera device.");
+
+ return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ int mode;
+ uint8_t fmt_reg, fmt_val;
+ uint8_t res_reg, res_val;
+ uint8_t fps_reg, fps_val;
+ uint8_t mode_val;
+
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+
+ if (mode & FORMAT_Y10B) {
+ fmt_reg = 0x19;
+ res_reg = 0x1a;
+ fps_reg = 0x1b;
+ mode_val = 0x03;
+ } else {
+ fmt_reg = 0x0c;
+ res_reg = 0x0d;
+ fps_reg = 0x0e;
+ mode_val = 0x01;
+ }
+
+ /* format */
+ if (mode & FORMAT_UYVY)
+ fmt_val = 0x05;
+ else
+ fmt_val = 0x00;
+
+ if (mode & MODE_1280x1024)
+ res_val = 0x02;
+ else
+ res_val = 0x01;
+
+ if (mode & FPS_HIGH)
+ fps_val = 0x1e;
+ else
+ fps_val = 0x0f;
+
+
+ /* turn off IR-reset function */
+ write_register(gspca_dev, 0x105, 0x00);
+
+ /* Reset video stream */
+ write_register(gspca_dev, 0x05, 0x00);
+
+ /* Due to some ridiculous condition in the firmware, we have to start
+ * and stop the depth stream before the camera will hand us 1280x1024
+ * IR. This is a stupid workaround, but we've yet to find a better
+ * solution.
+ *
+ * Thanks to Drew Fisher for figuring this out.
+ */
+ if (mode & (FORMAT_Y10B | MODE_1280x1024)) {
+ write_register(gspca_dev, 0x13, 0x01);
+ write_register(gspca_dev, 0x14, 0x1e);
+ write_register(gspca_dev, 0x06, 0x02);
+ write_register(gspca_dev, 0x06, 0x00);
+ }
+
+ write_register(gspca_dev, fmt_reg, fmt_val);
+ write_register(gspca_dev, res_reg, res_val);
+ write_register(gspca_dev, fps_reg, fps_val);
+
+ /* Start video stream */
+ write_register(gspca_dev, 0x05, mode_val);
+
+ /* disable Hflip */
+ write_register(gspca_dev, 0x47, 0x00);
+
+ return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* reset video stream */
+ write_register(gspca_dev, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ struct pkt_hdr *hdr = (void *)__data;
+ uint8_t *data = __data + sizeof(*hdr);
+ int datalen = len - sizeof(*hdr);
+
+ uint8_t sof = sd->stream_flag | 1;
+ uint8_t mof = sd->stream_flag | 2;
+ uint8_t eof = sd->stream_flag | 5;
+
+ if (len < 12)
+ return;
+
+ if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') {
+ warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag,
+ hdr->magic[0], hdr->magic[1]);
+ return;
+ }
+
+ if (hdr->flag == sof)
+ gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen);
+
+ else if (hdr->flag == mof)
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen);
+
+ else if (hdr->flag == eof)
+ gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen);
+
+ else
+ warn("Packet type not recognized...");
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ /*
+ .querymenu = sd_querymenu,
+ .get_streamparm = sd_get_streamparm,
+ .set_streamparm = sd_set_streamparm,
+ */
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x045e, 0x02ae)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- 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)
+{
+ return usb_register(&sd_driver);
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index cb4d0bf0d784..0196209a948a 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -361,7 +361,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
mi_w(gspca_dev, i + 1, mi_data[i]);
data[0] = 0x00;
- data[1] = 0x4d; /* ISOC transfering enable... */
+ data[1] = 0x4d; /* ISOC transferring enable... */
reg_w(gspca_dev, 2);
gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
index 3884c9d300c5..97e507967434 100644
--- a/drivers/media/video/gspca/mr97310a.c
+++ b/drivers/media/video/gspca/mr97310a.c
@@ -469,7 +469,7 @@ static void lcd_stop(struct gspca_dev *gspca_dev)
static int isoc_enable(struct gspca_dev *gspca_dev)
{
gspca_dev->usb_buf[0] = 0x00;
- gspca_dev->usb_buf[1] = 0x4d; /* ISOC transfering enable... */
+ gspca_dev->usb_buf[1] = 0x4d; /* ISOC transferring enable... */
return mr_write(gspca_dev, 2);
}
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index fd1b6082c96d..36a46fc78734 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -381,7 +381,7 @@ static const struct v4l2_pix_format ov519_sif_mode[] = {
larger then necessary, however they need to be this big as the ov511 /
ov518 always fills the entire isoc frame, using 0 padding bytes when
it doesn't have any data. So with low framerates the amount of data
- transfered can become quite large (libv4l will remove all the 0 padding
+ transferred can become quite large (libv4l will remove all the 0 padding
in userspace). */
static const struct v4l2_pix_format ov518_vga_mode[] = {
{320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
@@ -4368,7 +4368,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
gspca_dev->last_packet_type = DISCARD_PACKET;
return;
}
- /* Add 11 byte footer to frame, might be usefull */
+ /* Add 11 byte footer to frame, might be useful */
gspca_frame_add(gspca_dev, LAST_PACKET, in, 11);
return;
} else {
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 5a08738fba30..146b459b08d5 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -827,7 +827,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
possible to use less exposure then what the fps maximum
allows by setting register 10. register 10 configures the
actual exposure as quotient of the full exposure, with 0
- being no exposure at all (not very usefull) and reg10_max
+ being no exposure at all (not very useful) and reg10_max
being max exposure possible at that framerate.
The code maps our 0 - 510 ms exposure ctrl to these 2
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index 45552c3ff8d9..3e76951e3c19 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -607,7 +607,7 @@ static void spca500_reinit(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x00, 0x8880, 2);
/* family cam Quicksmart stuff */
reg_w(gspca_dev, 0x00, 0x800a, 0x00);
- /* Set agc transfer: synced inbetween frames */
+ /* Set agc transfer: synced between frames */
reg_w(gspca_dev, 0x00, 0x820f, 0x01);
/* Init SDRAM - needed for SDRAM access */
reg_w(gspca_dev, 0x00, 0x870a, 0x04);
@@ -831,7 +831,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* familycam Quicksmart pocketDV stuff */
reg_w(gspca_dev, 0x00, 0x800a, 0x00);
- /* Set agc transfer: synced inbetween frames */
+ /* Set agc transfer: synced between frames */
reg_w(gspca_dev, 0x00, 0x820f, 0x01);
/* Init SDRAM - needed for SDRAM access */
reg_w(gspca_dev, 0x00, 0x870a, 0x04);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 348319371523..9d0b46027b93 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -592,7 +592,7 @@ static const u16 spca508_sightcam_init_data[][2] = {
/* This line seems to setup the frame/canvas */
{0x000f, 0x8402},
-/* Theese 6 lines are needed to startup the webcam */
+/* These 6 lines are needed to startup the webcam */
{0x0090, 0x8110},
{0x0001, 0x8114},
{0x0001, 0x8114},
@@ -1375,7 +1375,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
- int data1, data2;
const u16 (*init_data)[2];
static const u16 (*(init_data_tb[]))[2] = {
spca508_vista_init_data, /* CreativeVista 0 */
@@ -1386,6 +1385,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
spca508_init_data, /* ViewQuestVQ110 5 */
};
+#ifdef GSPCA_DEBUG
+ int data1, data2;
+
/* Read from global register the USB product and vendor IDs, just to
* prove that we can communicate with the device. This works, which
* confirms at we are communicating properly and that the device
@@ -1400,6 +1402,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
data1 = reg_read(gspca_dev, 0x8621);
PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
+#endif
cam = &gspca_dev->cam;
cam->cam_mode = sif_mode;
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
index 2e9c06175192..5ba96aff2252 100644
--- a/drivers/media/video/gspca/sq905.c
+++ b/drivers/media/video/gspca/sq905.c
@@ -22,7 +22,7 @@
* History and Acknowledgments
*
* The original Linux driver for SQ905 based cameras was written by
- * Marcell Lengyel and furter developed by many other contributers
+ * Marcell Lengyel and furter developed by many other contributors
* and is available from http://sourceforge.net/projects/sqcam/
*
* This driver takes advantage of the reverse engineering work done for
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 87be52b5e1e3..763747700f10 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -436,17 +436,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
+ static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
+ if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
+ break;
+ strcpy((char *) menu->name, freq_nm[menu->index]);
+ return 0;
}
return -EINVAL;
}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
index 17531b41a073..b8156855f2b7 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -569,7 +569,7 @@ static int hdcs_init(struct sd *sd)
if (err < 0)
return err;
- /* Enable continous frame capture, bit 2: stop when frame complete */
+ /* Enable continuous frame capture, bit 2: stop when frame complete */
err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3));
if (err < 0)
return err;
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
index ac47b4c94388..75a5b9c2f15f 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -217,6 +217,8 @@ static int pb0100_start(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt)
+ return -ENODEV;
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
/* If we don't have enough bandwidth use a lower framerate */
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 543542af2720..b089c0d3ee9f 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -396,57 +396,6 @@ static void reg_w_riv(struct gspca_dev *gspca_dev,
req, index, value);
}
-/* read 1 byte */
-static u8 reg_r_1(struct gspca_dev *gspca_dev,
- u16 value) /* wValue */
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return 0;
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- 0x20, /* request */
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- 0, /* index */
- gspca_dev->usb_buf, 1,
- 500); /* timeout */
- if (ret < 0) {
- err("reg_r_1 err %d", ret);
- gspca_dev->usb_err = ret;
- return 0;
- }
- return gspca_dev->usb_buf[0];
-}
-
-/* read 1 or 2 bytes */
-static u16 reg_r_12(struct gspca_dev *gspca_dev,
- u8 req, /* bRequest */
- u16 index, /* wIndex */
- u16 length) /* wLength (1 or 2 only) */
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return 0;
- gspca_dev->usb_buf[1] = 0;
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, /* value */
- index,
- gspca_dev->usb_buf, length,
- 500);
- if (ret < 0) {
- err("reg_r_12 err %d", ret);
- gspca_dev->usb_err = ret;
- return 0;
- }
- return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
-}
-
static void write_vector(struct gspca_dev *gspca_dev,
const struct cmd *data, int ncmds)
{
@@ -473,44 +422,46 @@ static void setup_qtable(struct gspca_dev *gspca_dev,
static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req, u16 idx, u16 val)
{
- u16 notdone;
-
reg_w_riv(gspca_dev, req, idx, val);
- notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
+ PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
reg_w_riv(gspca_dev, req, idx, val);
- PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
-
msleep(200);
- notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
- PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
+ PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
}
+#ifdef GSPCA_DEBUG
static void spca504_read_info(struct gspca_dev *gspca_dev)
{
int i;
u8 info[6];
- for (i = 0; i < 6; i++)
- info[i] = reg_r_1(gspca_dev, i);
+ for (i = 0; i < 6; i++) {
+ reg_r(gspca_dev, 0, i, 1);
+ info[i] = gspca_dev->usb_buf[0];
+ }
PDEBUG(D_STREAM,
"Read info: %d %d %d %d %d %d."
" Should be 1,0,2,2,0,0",
info[0], info[1], info[2],
info[3], info[4], info[5]);
}
+#endif
static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req,
- u16 idx, u16 val, u16 endcode, u8 count)
+ u16 idx, u16 val, u8 endcode, u8 count)
{
u16 status;
reg_w_riv(gspca_dev, req, idx, val);
- status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
if (gspca_dev->usb_err < 0)
return;
- PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode);
+ PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
+ gspca_dev->usb_buf[0], endcode);
if (!count)
return;
count = 200;
@@ -518,7 +469,8 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
msleep(10);
/* gsmart mini2 write a each wait setting 1 ms is enough */
/* reg_w_riv(gspca_dev, req, idx, val); */
- status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
+ status = gspca_dev->usb_buf[0];
if (status == endcode) {
PDEBUG(D_FRAM, "status 0x%04x after wait %d",
status, 200 - count);
@@ -555,17 +507,19 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
}
}
+#ifdef GSPCA_DEBUG
static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
{
u8 *data;
data = gspca_dev->usb_buf;
reg_r(gspca_dev, 0x20, 0, 5);
- PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+ PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
data[0], data[1], data[2], data[3], data[4]);
reg_r(gspca_dev, 0x23, 0, 64);
reg_r(gspca_dev, 0x23, 1, 64);
}
+#endif
static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
{
@@ -578,7 +532,9 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
reg_w_riv(gspca_dev, 0x31, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
+#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
+#endif
reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
reg_r(gspca_dev, 0x24, 8, 1);
@@ -628,7 +584,8 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev)
cnt = 256;
while (--cnt > 0) {
/* With this we get the status, when return 0 it's all ok */
- if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
+ reg_r(gspca_dev, 0x06, 0x00, 1);
+ if (gspca_dev->usb_buf[0] == 0)
return;
msleep(10);
}
@@ -772,10 +729,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* fall thru */
case BRIDGE_SPCA533:
spca504B_PollingDataReady(gspca_dev);
+#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
+#endif
break;
case BRIDGE_SPCA536:
+#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
+#endif
reg_r(gspca_dev, 0x00, 0x5002, 1);
reg_w_1(gspca_dev, 0x24, 0, 0, 0);
reg_r(gspca_dev, 0x24, 0, 1);
@@ -801,7 +762,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA504: */
PDEBUG(D_STREAM, "Opening SPCA504");
if (sd->subtype == AiptekMiniPenCam13) {
+#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
+#endif
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -873,7 +836,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
case BRIDGE_SPCA504:
if (sd->subtype == AiptekMiniPenCam13) {
+#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
+#endif
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -885,7 +850,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
0, 0, 0x9d, 1);
} else {
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
+#endif
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
}
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index a3eccd815766..7e762d551099 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -92,8 +92,6 @@ static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_querymenu(struct gspca_dev *gspca_dev,
- struct v4l2_querymenu *menu);
static const struct ctrl sd_ctrls[] = {
{
@@ -1379,17 +1377,14 @@ static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
+ static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
+ if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
+ break;
+ strcpy((char *) menu->name, freq_nm[menu->index]);
+ return 0;
case V4L2_CID_EFFECTS:
if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
strncpy((char *) menu->name,
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index fa164e861cde..61cdd56a74a9 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -3065,15 +3065,10 @@ static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */
{0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
{0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
{0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
- {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
- {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
{}
};
-static const struct usb_action mc501cb_50HZScale[] = {
+static const struct usb_action mc501cb_50HZ[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
@@ -3082,15 +3077,10 @@ static const struct usb_action mc501cb_50HZScale[] = {
{0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */
{0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */
{0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
- {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
- {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
{}
};
-static const struct usb_action mc501cb_50HZ[] = {
+static const struct usb_action mc501cb_50HZScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
@@ -3099,15 +3089,10 @@ static const struct usb_action mc501cb_50HZ[] = {
{0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */
{0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */
{0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
- {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
- {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
{}
};
-static const struct usb_action mc501cb_60HZScale[] = {
+static const struct usb_action mc501cb_60HZ[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3116,15 +3101,10 @@ static const struct usb_action mc501cb_60HZScale[] = {
{0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
{0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
{0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
- {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
- {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
{}
};
-static const struct usb_action mc501cb_60HZ[] = {
+static const struct usb_action mc501cb_60HZScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -3133,15 +3113,10 @@ static const struct usb_action mc501cb_60HZ[] = {
{0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
{0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
{0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
- {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
- {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
{}
};
-static const struct usb_action mc501cb_NoFlikerScale[] = {
+static const struct usb_action mc501cb_NoFliker[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3150,15 +3125,10 @@ static const struct usb_action mc501cb_NoFlikerScale[] = {
{0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
{0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
{0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
- {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
- {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
{}
};
-static const struct usb_action mc501cb_NoFliker[] = {
+static const struct usb_action mc501cb_NoFlikerScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -6296,7 +6266,6 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 retbyte;
u16 retword;
/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
@@ -6389,8 +6358,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */
PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword);
if (retword == 0x2030) {
+#ifdef GSPCA_DEBUG
+ u8 retbyte;
+
retbyte = i2c_read(gspca_dev, 0x02); /* revision number */
PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
+#endif
send_unknown(gspca_dev, SENSOR_PO2030);
return retword;
}
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index cdf8b191f710..cbc505a2fc29 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -261,7 +261,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
/* the saa7146 provides some controls (brightness, contrast, saturation)
which gets registered *after* this function. because of this we have
- to return with a value != 0 even if the function succeded.. */
+ to return with a value != 0 even if the function succeeded.. */
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
index 1a1169115716..0382ea752e6f 100644
--- a/drivers/media/video/imx074.c
+++ b/drivers/media/video/imx074.c
@@ -298,7 +298,7 @@ static unsigned long imx074_query_bus_param(struct soc_camera_device *icd)
static int imx074_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
- return -1;
+ return -EINVAL;
}
static struct soc_camera_ops imx074_ops = {
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 39946420b301..a4e4dfdbc2f2 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -810,7 +810,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
u16 cmd;
- u8 card_rev;
unsigned char pci_latency;
IVTV_DEBUG_INFO("Enabling pci device\n");
@@ -857,7 +856,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
}
IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev);
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 64 && ivtv_pci_latency) {
@@ -874,7 +872,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
"irq: %d, latency: %d, memory: 0x%lx\n",
- pdev->device, card_rev, pdev->bus->number,
+ pdev->device, pdev->revision, pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
pdev->irq, pci_latency, (unsigned long)itv->base_addr);
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index 4df01947a7df..14a1cea1d70d 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -179,7 +179,7 @@ static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile
{
int i;
- /* mailbox is preceeded by a 16 byte 'magic cookie' starting at a 256-byte
+ /* mailbox is preceded by a 16 byte 'magic cookie' starting at a 256-byte
address boundary */
for (i = 0; i < size; i += 0x100) {
if (readl(mem + i) == 0x12345678 &&
@@ -377,7 +377,7 @@ int ivtv_firmware_check(struct ivtv *itv, char *where)
"Reloading\n", where);
res = ivtv_firmware_restart(itv);
/*
- * Even if restarted ok, still signal a problem had occured.
+ * Even if restarted ok, still signal a problem had occurred.
* The caller can come through this function again to check
* if things are really ok after the restart.
*/
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index f0316d02f09f..17247451c693 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -1080,7 +1080,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
if (!oi->ivtvfb_info.pseudo_palette) {
- IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
+ IVTVFB_ERR("abort, unable to alloc pseudo palette\n");
return -ENOMEM;
}
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index 5e1c9a81984c..303ffa7df4ac 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -174,7 +174,7 @@ static int m52790_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index b1763ac93ab3..de5d481b0328 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -69,7 +69,7 @@ MODULE_LICENSE("GPL");
/* module parameters */
static int opmode = OPMODE_AUTO;
int msp_debug; /* msp_debug output */
-int msp_once; /* no continous stereo monitoring */
+int msp_once; /* no continuous stereo monitoring */
int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france),
the autoscan seems work well only with FM... */
int msp_standard = 1; /* Override auto detect of audio msp_standard,
@@ -96,7 +96,7 @@ MODULE_PARM_DESC(debug, "Enable debug messages [0-3]");
MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
-MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
+MODULE_PARM_DESC(dolby, "Activates Dolby processing");
/* ---------------------------------------------------------------------- */
@@ -551,7 +551,7 @@ static int msp_log_status(struct v4l2_subdev *sd)
switch (state->mode) {
case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
- case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break;
+ case MSP_MODE_FM_TERRA: p = "Terrestrial FM-mono/stereo"; break;
case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index b376fcdee652..80387e2c3eca 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -87,7 +87,7 @@ static struct msp3400c_init_data_dem {
{-8, -8, 4, 6, 78, 107},
MSP_CARRIER(10.7), MSP_CARRIER(10.7),
0x00d0, 0x0480, 0x0020, 0x3000
- }, { /* Terrestial FM-mono + FM-stereo */
+ }, { /* Terrestrial FM-mono + FM-stereo */
{3, 18, 27, 48, 66, 72},
{3, 18, 27, 48, 66, 72},
MSP_CARRIER(5.5), MSP_CARRIER(5.5),
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 53fa2a7bf156..ebebed929627 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -315,10 +315,20 @@ static int mt9m111_setup_rect(struct i2c_client *client,
static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
{
int ret;
+ u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB |
+ MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN |
+ MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
+ MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr |
+ MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
- ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
+ ret = reg_read(OUTPUT_FORMAT_CTRL2_A);
+ if (ret >= 0)
+ ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt);
if (!ret)
- ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt);
+ ret = reg_read(OUTPUT_FORMAT_CTRL2_B);
+ if (ret >= 0)
+ ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt);
+
return ret;
}
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index e313d8390092..fc76ed1c08e5 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -228,7 +228,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
flags = soc_camera_apply_sensor_flags(icl, flags);
- if (flags & SOCAM_PCLK_SAMPLE_RISING)
+ if (flags & SOCAM_PCLK_SAMPLE_FALLING)
pixclk |= 0x10;
if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
new file mode 100644
index 000000000000..1319c2c48aff
--- /dev/null
+++ b/drivers/media/video/mt9v032.c
@@ -0,0 +1,773 @@
+/*
+ * Driver for MT9V032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on the MT9M001 driver,
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/mt9v032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9V032_PIXEL_ARRAY_HEIGHT 492
+#define MT9V032_PIXEL_ARRAY_WIDTH 782
+
+#define MT9V032_CHIP_VERSION 0x00
+#define MT9V032_CHIP_ID_REV1 0x1311
+#define MT9V032_CHIP_ID_REV3 0x1313
+#define MT9V032_ROW_START 0x01
+#define MT9V032_ROW_START_MIN 4
+#define MT9V032_ROW_START_DEF 10
+#define MT9V032_ROW_START_MAX 482
+#define MT9V032_COLUMN_START 0x02
+#define MT9V032_COLUMN_START_MIN 1
+#define MT9V032_COLUMN_START_DEF 2
+#define MT9V032_COLUMN_START_MAX 752
+#define MT9V032_WINDOW_HEIGHT 0x03
+#define MT9V032_WINDOW_HEIGHT_MIN 1
+#define MT9V032_WINDOW_HEIGHT_DEF 480
+#define MT9V032_WINDOW_HEIGHT_MAX 480
+#define MT9V032_WINDOW_WIDTH 0x04
+#define MT9V032_WINDOW_WIDTH_MIN 1
+#define MT9V032_WINDOW_WIDTH_DEF 752
+#define MT9V032_WINDOW_WIDTH_MAX 752
+#define MT9V032_HORIZONTAL_BLANKING 0x05
+#define MT9V032_HORIZONTAL_BLANKING_MIN 43
+#define MT9V032_HORIZONTAL_BLANKING_MAX 1023
+#define MT9V032_VERTICAL_BLANKING 0x06
+#define MT9V032_VERTICAL_BLANKING_MIN 4
+#define MT9V032_VERTICAL_BLANKING_MAX 3000
+#define MT9V032_CHIP_CONTROL 0x07
+#define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3)
+#define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7)
+#define MT9V032_CHIP_CONTROL_SEQUENTIAL (1 << 8)
+#define MT9V032_SHUTTER_WIDTH1 0x08
+#define MT9V032_SHUTTER_WIDTH2 0x09
+#define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a
+#define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b
+#define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1
+#define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480
+#define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767
+#define MT9V032_RESET 0x0c
+#define MT9V032_READ_MODE 0x0d
+#define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0)
+#define MT9V032_READ_MODE_ROW_BIN_SHIFT 0
+#define MT9V032_READ_MODE_COLUMN_BIN_MASK (3 << 2)
+#define MT9V032_READ_MODE_COLUMN_BIN_SHIFT 2
+#define MT9V032_READ_MODE_ROW_FLIP (1 << 4)
+#define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5)
+#define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6)
+#define MT9V032_READ_MODE_DARK_ROWS (1 << 7)
+#define MT9V032_PIXEL_OPERATION_MODE 0x0f
+#define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2)
+#define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6)
+#define MT9V032_ANALOG_GAIN 0x35
+#define MT9V032_ANALOG_GAIN_MIN 16
+#define MT9V032_ANALOG_GAIN_DEF 16
+#define MT9V032_ANALOG_GAIN_MAX 64
+#define MT9V032_MAX_ANALOG_GAIN 0x36
+#define MT9V032_MAX_ANALOG_GAIN_MAX 127
+#define MT9V032_FRAME_DARK_AVERAGE 0x42
+#define MT9V032_DARK_AVG_THRESH 0x46
+#define MT9V032_DARK_AVG_LOW_THRESH_MASK (255 << 0)
+#define MT9V032_DARK_AVG_LOW_THRESH_SHIFT 0
+#define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8)
+#define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8
+#define MT9V032_ROW_NOISE_CORR_CONTROL 0x70
+#define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5)
+#define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7)
+#define MT9V032_PIXEL_CLOCK 0x74
+#define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0)
+#define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1)
+#define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2)
+#define MT9V032_PIXEL_CLOCK_CONT_LINE (1 << 3)
+#define MT9V032_PIXEL_CLOCK_INV_PXL_CLK (1 << 4)
+#define MT9V032_TEST_PATTERN 0x7f
+#define MT9V032_TEST_PATTERN_DATA_MASK (1023 << 0)
+#define MT9V032_TEST_PATTERN_DATA_SHIFT 0
+#define MT9V032_TEST_PATTERN_USE_DATA (1 << 10)
+#define MT9V032_TEST_PATTERN_GRAY_MASK (3 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_NONE (0 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_VERTICAL (1 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11)
+#define MT9V032_TEST_PATTERN_ENABLE (1 << 13)
+#define MT9V032_TEST_PATTERN_FLIP (1 << 14)
+#define MT9V032_AEC_AGC_ENABLE 0xaf
+#define MT9V032_AEC_ENABLE (1 << 0)
+#define MT9V032_AGC_ENABLE (1 << 1)
+#define MT9V032_THERMAL_INFO 0xc1
+
+struct mt9v032 {
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_rect crop;
+
+ struct v4l2_ctrl_handler ctrls;
+
+ struct mutex power_lock;
+ int power_count;
+
+ struct mt9v032_platform_data *pdata;
+ u16 chip_control;
+ u16 aec_agc;
+};
+
+static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct mt9v032, subdev);
+}
+
+static int mt9v032_read(struct i2c_client *client, const u8 reg)
+{
+ s32 data = i2c_smbus_read_word_data(client, reg);
+ dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
+ swab16(data), reg);
+ return data < 0 ? data : swab16(data);
+}
+
+static int mt9v032_write(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
+ data, reg);
+ return i2c_smbus_write_word_data(client, reg, swab16(data));
+}
+
+static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 value = (mt9v032->chip_control & ~clear) | set;
+ int ret;
+
+ ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
+ if (ret < 0)
+ return ret;
+
+ mt9v032->chip_control = value;
+ return 0;
+}
+
+static int
+mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 value = mt9v032->aec_agc;
+ int ret;
+
+ if (enable)
+ value |= which;
+ else
+ value &= ~which;
+
+ ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
+ if (ret < 0)
+ return ret;
+
+ mt9v032->aec_agc = value;
+ return 0;
+}
+
+static int mt9v032_power_on(struct mt9v032 *mt9v032)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ int ret;
+
+ if (mt9v032->pdata->set_clock) {
+ mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000);
+ udelay(1);
+ }
+
+ /* Reset the chip and stop data read out */
+ ret = mt9v032_write(client, MT9V032_RESET, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
+}
+
+static void mt9v032_power_off(struct mt9v032 *mt9v032)
+{
+ if (mt9v032->pdata->set_clock)
+ mt9v032->pdata->set_clock(&mt9v032->subdev, 0);
+}
+
+static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ int ret;
+
+ if (!on) {
+ mt9v032_power_off(mt9v032);
+ return 0;
+ }
+
+ ret = mt9v032_power_on(mt9v032);
+ if (ret < 0)
+ return ret;
+
+ /* Configure the pixel clock polarity */
+ if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
+ ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
+ MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Disable the noise correction algorithm and restore the controls. */
+ ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
+ if (ret < 0)
+ return ret;
+
+ return v4l2_ctrl_handler_setup(&mt9v032->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9v032->format;
+ default:
+ return NULL;
+ }
+}
+
+static struct v4l2_rect *
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9v032->crop;
+ default:
+ return NULL;
+ }
+}
+
+static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
+ | MT9V032_CHIP_CONTROL_DOUT_ENABLE
+ | MT9V032_CHIP_CONTROL_SEQUENTIAL;
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *format = &mt9v032->format;
+ struct v4l2_rect *crop = &mt9v032->crop;
+ unsigned int hratio;
+ unsigned int vratio;
+ int ret;
+
+ if (!enable)
+ return mt9v032_set_chip_control(mt9v032, mode, 0);
+
+ /* Configure the window size and row/column bin */
+ hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
+ vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
+
+ ret = mt9v032_write(client, MT9V032_READ_MODE,
+ (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
+ (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
+ max(43, 660 - crop->width));
+ if (ret < 0)
+ return ret;
+
+ /* Switch to master "normal" mode */
+ return mt9v032_set_chip_control(mt9v032, 0, mode);
+}
+
+static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ return 0;
+}
+
+static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+ return -EINVAL;
+
+ fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
+ fse->max_width = fse->min_width;
+ fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int mt9v032_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->which);
+ return 0;
+}
+
+static int mt9v032_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop;
+ unsigned int width;
+ unsigned int height;
+ unsigned int hratio;
+ unsigned int vratio;
+
+ __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
+ format->which);
+
+ /* Clamp the width and height to avoid dividing by zero. */
+ width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+ max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
+ __crop->width);
+ height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+ max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
+ __crop->height);
+
+ hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+ vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+ __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->which);
+ __format->width = __crop->width / hratio;
+ __format->height = __crop->height / vratio;
+
+ format->format = *__format;
+
+ return 0;
+}
+
+static int mt9v032_get_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
+ crop->which);
+ return 0;
+}
+
+static int mt9v032_set_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop;
+ struct v4l2_rect rect;
+
+ /* Clamp the crop rectangle boundaries and align them to a multiple of 2
+ * pixels.
+ */
+ rect.left = clamp(ALIGN(crop->rect.left, 2),
+ MT9V032_COLUMN_START_MIN,
+ MT9V032_COLUMN_START_MAX);
+ rect.top = clamp(ALIGN(crop->rect.top, 2),
+ MT9V032_ROW_START_MIN,
+ MT9V032_ROW_START_MAX);
+ rect.width = clamp(ALIGN(crop->rect.width, 2),
+ MT9V032_WINDOW_WIDTH_MIN,
+ MT9V032_WINDOW_WIDTH_MAX);
+ rect.height = clamp(ALIGN(crop->rect.height, 2),
+ MT9V032_WINDOW_HEIGHT_MIN,
+ MT9V032_WINDOW_HEIGHT_MAX);
+
+ rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
+ rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+ __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
+
+ if (rect.width != __crop->width || rect.height != __crop->height) {
+ /* Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
+ crop->which);
+ __format->width = rect.width;
+ __format->height = rect.height;
+ }
+
+ *__crop = rect;
+ crop->rect = rect;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
+
+static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9v032 *mt9v032 =
+ container_of(ctrl->handler, struct mt9v032, ctrls);
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE,
+ ctrl->val);
+
+ case V4L2_CID_GAIN:
+ return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
+ ctrl->val);
+
+ case V4L2_CID_EXPOSURE:
+ return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
+ ctrl->val);
+
+ case V4L2_CID_TEST_PATTERN:
+ switch (ctrl->val) {
+ case 0:
+ data = 0;
+ break;
+ case 1:
+ data = MT9V032_TEST_PATTERN_GRAY_VERTICAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ case 2:
+ data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ case 3:
+ data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ default:
+ data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT)
+ | MT9V032_TEST_PATTERN_USE_DATA
+ | MT9V032_TEST_PATTERN_ENABLE
+ | MT9V032_TEST_PATTERN_FLIP;
+ break;
+ }
+
+ return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
+ }
+
+ return 0;
+}
+
+static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
+ .s_ctrl = mt9v032_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config mt9v032_ctrls[] = {
+ {
+ .ops = &mt9v032_ctrl_ops,
+ .id = V4L2_CID_TEST_PATTERN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Test pattern",
+ .min = 0,
+ .max = 1023,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ }
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9v032_set_power(struct v4l2_subdev *subdev, int on)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ int ret = 0;
+
+ mutex_lock(&mt9v032->power_lock);
+
+ /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+ * update the power state.
+ */
+ if (mt9v032->power_count == !on) {
+ ret = __mt9v032_set_power(mt9v032, !!on);
+ if (ret < 0)
+ goto done;
+ }
+
+ /* Update the power count. */
+ mt9v032->power_count += on ? 1 : -1;
+ WARN_ON(mt9v032->power_count < 0);
+
+done:
+ mutex_unlock(&mt9v032->power_lock);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9v032_registered(struct v4l2_subdev *subdev)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ s32 data;
+ int ret;
+
+ dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
+ client->addr);
+
+ ret = mt9v032_power_on(mt9v032);
+ if (ret < 0) {
+ dev_err(&client->dev, "MT9V032 power up failed\n");
+ return ret;
+ }
+
+ /* Read and check the sensor version */
+ data = mt9v032_read(client, MT9V032_CHIP_VERSION);
+ if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
+ dev_err(&client->dev, "MT9V032 not detected, wrong version "
+ "0x%04x\n", data);
+ return -ENODEV;
+ }
+
+ mt9v032_power_off(mt9v032);
+
+ dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
+ client->addr);
+
+ return ret;
+}
+
+static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ crop = v4l2_subdev_get_try_crop(fh, 0);
+ crop->left = MT9V032_COLUMN_START_DEF;
+ crop->top = MT9V032_ROW_START_DEF;
+ crop->width = MT9V032_WINDOW_WIDTH_DEF;
+ crop->height = MT9V032_WINDOW_HEIGHT_DEF;
+
+ format = v4l2_subdev_get_try_format(fh, 0);
+ format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format->width = MT9V032_WINDOW_WIDTH_DEF;
+ format->height = MT9V032_WINDOW_HEIGHT_DEF;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return mt9v032_set_power(subdev, 1);
+}
+
+static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return mt9v032_set_power(subdev, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
+ .s_power = mt9v032_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
+ .s_stream = mt9v032_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
+ .enum_mbus_code = mt9v032_enum_mbus_code,
+ .enum_frame_size = mt9v032_enum_frame_size,
+ .get_fmt = mt9v032_get_format,
+ .set_fmt = mt9v032_set_format,
+ .get_crop = mt9v032_get_crop,
+ .set_crop = mt9v032_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9v032_subdev_ops = {
+ .core = &mt9v032_subdev_core_ops,
+ .video = &mt9v032_subdev_video_ops,
+ .pad = &mt9v032_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
+ .registered = mt9v032_registered,
+ .open = mt9v032_open,
+ .close = mt9v032_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9v032_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9v032 *mt9v032;
+ unsigned int i;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&client->adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
+ if (!mt9v032)
+ return -ENOMEM;
+
+ mutex_init(&mt9v032->power_lock);
+ mt9v032->pdata = client->dev.platform_data;
+
+ v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4);
+
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN,
+ MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF);
+ v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
+ V4L2_EXPOSURE_AUTO);
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
+ MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
+ MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
+
+ for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i)
+ v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL);
+
+ mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
+
+ if (mt9v032->ctrls.error)
+ printk(KERN_INFO "%s: control initialization error %d\n",
+ __func__, mt9v032->ctrls.error);
+
+ mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
+ mt9v032->crop.top = MT9V032_ROW_START_DEF;
+ mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
+ mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
+
+ mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
+ mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
+ mt9v032->format.field = V4L2_FIELD_NONE;
+ mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+ mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
+
+ v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
+ mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
+ mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+ if (ret < 0)
+ kfree(mt9v032);
+
+ return ret;
+}
+
+static int mt9v032_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ v4l2_device_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+ kfree(mt9v032);
+ return 0;
+}
+
+static const struct i2c_device_id mt9v032_id[] = {
+ { "mt9v032", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v032_id);
+
+static struct i2c_driver mt9v032_driver = {
+ .driver = {
+ .name = "mt9v032",
+ },
+ .probe = mt9v032_probe,
+ .remove = mt9v032_remove,
+ .id_table = mt9v032_id,
+};
+
+static int __init mt9v032_init(void)
+{
+ return i2c_add_driver(&mt9v032_driver);
+}
+
+static void __exit mt9v032_exit(void)
+{
+ i2c_del_driver(&mt9v032_driver);
+}
+
+module_init(mt9v032_init);
+module_exit(mt9v032_exit);
+
+MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 502e2a40964c..c7680eb83664 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -400,6 +400,35 @@ static int mx3_videobuf_init(struct vb2_buffer *vb)
return 0;
}
+static int mx3_stop_streaming(struct vb2_queue *q)
+{
+ struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+ 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];
+ struct dma_chan *chan;
+ struct mx3_camera_buffer *buf, *tmp;
+ unsigned long flags;
+
+ if (ichan) {
+ chan = &ichan->dma_chan;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ }
+
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+
+ mx3_cam->active = NULL;
+
+ list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
+ buf->state = CSI_BUF_NEEDS_INIT;
+ list_del_init(&buf->queue);
+ }
+
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+ return 0;
+}
+
static struct vb2_ops mx3_videobuf_ops = {
.queue_setup = mx3_videobuf_setup,
.buf_prepare = mx3_videobuf_prepare,
@@ -408,6 +437,7 @@ static struct vb2_ops mx3_videobuf_ops = {
.buf_init = mx3_videobuf_init,
.wait_prepare = soc_camera_unlock,
.wait_finish = soc_camera_lock,
+ .stop_streaming = mx3_stop_streaming,
};
static int mx3_camera_init_videobuf(struct vb2_queue *q,
@@ -658,8 +688,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(icd->dev.parent,
- "Invalid format code #%u: %d\n", idx, code);
+ dev_warn(icd->dev.parent,
+ "Unsupported format code #%u: %d\n", idx, code);
return 0;
}
@@ -712,13 +742,9 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
static void configure_geometry(struct mx3_camera_dev *mx3_cam,
unsigned int width, unsigned int height,
- enum v4l2_mbus_pixelcode code)
+ const struct soc_mbus_pixelfmt *fmt)
{
u32 ctrl, width_field, height_field;
- const struct soc_mbus_pixelfmt *fmt;
-
- fmt = soc_mbus_get_fmtdesc(code);
- BUG_ON(!fmt);
if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
/*
@@ -726,8 +752,10 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam,
* the width parameter count the number of samples to
* capture to complete the whole image width.
*/
- width *= soc_mbus_samples_per_pixel(fmt);
- BUG_ON(width < 0);
+ unsigned int num, den;
+ int ret = soc_mbus_samples_per_pixel(fmt, &num, &den);
+ BUG_ON(ret < 0);
+ width = width * num / den;
}
/* Setup frame size - this cannot be changed on-the-fly... */
@@ -774,8 +802,8 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
*/
static inline void stride_align(__u32 *width)
{
- if (((*width + 7) & ~7) < 4096)
- *width = (*width + 7) & ~7;
+ if (ALIGN(*width, 8) < 4096)
+ *width = ALIGN(*width, 8);
else
*width = *width & ~7;
}
@@ -801,11 +829,14 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
if (ret < 0)
return ret;
- /* The capture device might have changed its output */
+ /* The capture device might have changed its output sizes */
ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
if (ret < 0)
return ret;
+ if (mf.code != icd->current_fmt->code)
+ return -EINVAL;
+
if (mf.width & 7) {
/* Ouch! We can only handle 8-byte aligned width... */
stride_align(&mf.width);
@@ -815,7 +846,8 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
}
if (mf.width != icd->user_width || mf.height != icd->user_height)
- configure_geometry(mx3_cam, mf.width, mf.height, mf.code);
+ configure_geometry(mx3_cam, mf.width, mf.height,
+ icd->current_fmt->host_fmt);
dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
mf.width, mf.height);
@@ -853,7 +885,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
* mxc_v4l2_s_fmt()
*/
- configure_geometry(mx3_cam, pix->width, pix->height, xlate->code);
+ configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt);
mf.width = pix->width;
mf.height = pix->height;
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 029a4babfd61..d4fe7bc92a1d 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -473,7 +473,7 @@ static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
/*
* Convert V4L2 rotation to DSS rotation
* V4L2 understand 0, 90, 180, 270.
- * Convert to 0, 1, 2 and 3 repsectively for DSS
+ * Convert to 0, 1, 2 and 3 respectively for DSS
*/
static int v4l2_rot_to_dss_rot(int v4l2_rotation,
enum dss_rotation *rotation, bool mirror)
@@ -1142,7 +1142,7 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q,
}
/*
- * Buffer queue funtion will be called from the videobuf layer when _QBUF
+ * Buffer queue function will be called from the videobuf layer when _QBUF
* ioctl is called. It is used to enqueue buffer, which is ready to be
* displayed.
*/
diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c
index b941c761eef9..2aa6a76c5e59 100644
--- a/drivers/media/video/omap/omap_voutlib.c
+++ b/drivers/media/video/omap/omap_voutlib.c
@@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(omap_vout_default_crop);
/* Given a new render window in new_win, adjust the window to the
* nearest supported configuration. The adjusted window parameters are
* returned in new_win.
- * Returns zero if succesful, or -EINVAL if the requested window is
+ * Returns zero if successful, or -EINVAL if the requested window is
* impossible and cannot reasonably be adjusted.
*/
int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
@@ -101,7 +101,7 @@ EXPORT_SYMBOL_GPL(omap_vout_try_window);
* will also be adjusted if necessary. Preference is given to keeping the
* the window as close to the requested configuration as possible. If
* successful, new_win, vout->win, and crop are updated.
- * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * Returns zero if successful, or -EINVAL if the requested preview window is
* impossible and cannot reasonably be adjusted.
*/
int omap_vout_new_window(struct v4l2_rect *crop,
@@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(omap_vout_new_window);
* window would fall outside the display boundaries, the cropping rectangle
* will also be adjusted to maintain the rescaling ratios. If successful, crop
* and win are updated.
- * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is
+ * Returns zero if successful, or -EINVAL if the requested cropping rectangle is
* impossible and cannot reasonably be adjusted.
*/
int omap_vout_new_crop(struct v4l2_pix_format *pix,
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
index eab31cbd68eb..e7cfc85b0a1c 100644
--- a/drivers/media/video/omap1_camera.c
+++ b/drivers/media/video/omap1_camera.c
@@ -687,7 +687,7 @@ static void videobuf_done(struct omap1_cam_dev *pcdev,
* In CONTIG mode, the current buffer parameters had already
* been entered into the DMA programming register set while the
* buffer was fetched with prepare_next_vb(), they may have also
- * been transfered into the runtime set and already active if
+ * been transferred into the runtime set and already active if
* the DMA still running.
*/
} else {
@@ -835,7 +835,7 @@ static irqreturn_t cam_isr(int irq, void *data)
/*
* If exactly 2 sgbufs from the next sglist have
* been programmed into the DMA engine (the
- * frist one already transfered into the DMA
+ * first one already transferred into the DMA
* runtime register set, the second one still
* in the programming set), then we are in sync.
*/
@@ -990,63 +990,80 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd)
}
/* Duplicate standard formats based on host capability of byte swapping */
-static const struct soc_mbus_pixelfmt omap1_cam_formats[] = {
- [V4L2_MBUS_FMT_UYVY8_2X8] = {
+static const struct soc_mbus_lookup omap1_cam_formats[] = {
+{
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_VYUY8_2X8] = {
+}, {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_YUYV8_2X8] = {
+}, {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_YVYU8_2X8] = {
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555,
.name = "RGB555",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555X,
.name = "RGB555X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB565_2X8_BE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB565_2X8_LE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565X,
.name = "RGB565X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
+},
};
static int omap1_cam_get_formats(struct soc_camera_device *icd,
@@ -1065,7 +1082,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(dev, "%s: invalid format code #%d: %d\n", __func__,
+ dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__,
idx, code);
return 0;
}
@@ -1085,12 +1102,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
case V4L2_MBUS_FMT_RGB565_2X8_LE:
formats++;
if (xlate) {
- xlate->host_fmt = &omap1_cam_formats[code];
+ xlate->host_fmt = soc_mbus_find_fmtdesc(code,
+ omap1_cam_formats,
+ ARRAY_SIZE(omap1_cam_formats));
xlate->code = code;
xlate++;
dev_dbg(dev,
"%s: providing format %s as byte swapped code #%d\n",
- __func__, omap1_cam_formats[code].name, code);
+ __func__, xlate->host_fmt->name, code);
}
default:
if (xlate)
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index 1a9963bd6d40..472a69359e60 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -215,20 +215,21 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
}
switch (xclksel) {
- case 0:
+ case ISP_XCLK_A:
isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
ISPTCTRL_CTRL_DIVA_MASK,
divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
currentxclk);
break;
- case 1:
+ case ISP_XCLK_B:
isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
ISPTCTRL_CTRL_DIVB_MASK,
divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
currentxclk);
break;
+ case ISP_XCLK_NONE:
default:
omap3isp_put(isp);
dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
@@ -237,13 +238,13 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
}
/* Do we go from stable whatever to clock? */
- if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2)
+ if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2)
omap3isp_get(isp);
/* Stopping the clock. */
- else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2)
+ else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2)
omap3isp_put(isp);
- isp->xclk_divisor[xclksel] = divisor;
+ isp->xclk_divisor[xclksel - 1] = divisor;
omap3isp_put(isp);
@@ -285,7 +286,8 @@ static void isp_power_settings(struct isp_device *isp, int idle)
*/
void omap3isp_configure_bridge(struct isp_device *isp,
enum ccdc_input_entity input,
- const struct isp_parallel_platform_data *pdata)
+ const struct isp_parallel_platform_data *pdata,
+ unsigned int shift)
{
u32 ispctrl_val;
@@ -298,9 +300,9 @@ void omap3isp_configure_bridge(struct isp_device *isp,
switch (input) {
case CCDC_INPUT_PARALLEL:
ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
- ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT;
ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT;
+ shift += pdata->data_lane_shift * 2;
break;
case CCDC_INPUT_CSI2A:
@@ -319,6 +321,8 @@ void omap3isp_configure_bridge(struct isp_device *isp,
return;
}
+ ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK;
+
ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK;
ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE;
@@ -658,6 +662,8 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
/* Apply power change to connected non-nodes. */
ret = isp_pipeline_pm_power(entity, change);
+ if (ret < 0)
+ entity->use_count -= change;
mutex_unlock(&entity->parent->graph_mutex);
@@ -715,7 +721,7 @@ static int isp_pipeline_link_notify(struct media_pad *source,
* Walk the entities chain starting at the pipeline output video node and start
* all modules in the chain in the given mode.
*
- * Return 0 if successfull, or the return value of the failed video::s_stream
+ * Return 0 if successful, or the return value of the failed video::s_stream
* operation otherwise.
*/
static int isp_pipeline_enable(struct isp_pipeline *pipe,
@@ -872,6 +878,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
}
}
+ if (failure < 0)
+ isp->needs_reset = true;
+
return failure;
}
@@ -883,8 +892,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
* Set the pipeline to the given stream state. Pipelines can be started in
* single-shot or continuous mode.
*
- * Return 0 if successfull, or the return value of the failed video::s_stream
- * operation otherwise.
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise. The pipeline state is not updated when the operation
+ * fails, except when stopping the pipeline.
*/
int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
enum isp_pipeline_stream_state state)
@@ -895,7 +905,9 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
ret = isp_pipeline_disable(pipe);
else
ret = isp_pipeline_enable(pipe, state);
- pipe->stream_state = state;
+
+ if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED)
+ pipe->stream_state = state;
return ret;
}
@@ -1283,7 +1295,7 @@ static void __isp_subclk_update(struct isp_device *isp)
clk |= ISPCTRL_RSZ_CLK_EN;
/* NOTE: For CCDC & Preview submodules, we need to affect internal
- * RAM aswell.
+ * RAM as well.
*/
if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC)
clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN;
@@ -1431,7 +1443,7 @@ static int isp_get_clocks(struct isp_device *isp)
* Increment the reference count on the ISP. If the first reference is taken,
* enable clocks and power-up all submodules.
*
- * Return a pointer to the ISP device structure, or NULL if an error occured.
+ * Return a pointer to the ISP device structure, or NULL if an error occurred.
*/
struct isp_device *omap3isp_get(struct isp_device *isp)
{
@@ -1481,6 +1493,10 @@ void omap3isp_put(struct isp_device *isp)
if (--isp->ref_count == 0) {
isp_disable_interrupts(isp);
isp_save_ctx(isp);
+ if (isp->needs_reset) {
+ isp_reset(isp);
+ isp->needs_reset = false;
+ }
isp_disable_clocks(isp);
}
mutex_unlock(&isp->isp_mutex);
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
index cf5214e95a92..2620c405f5e4 100644
--- a/drivers/media/video/omap3isp/isp.h
+++ b/drivers/media/video/omap3isp/isp.h
@@ -132,7 +132,6 @@ struct isp_reg {
/**
* struct isp_parallel_platform_data - Parallel interface platform data
- * @width: Parallel bus width in bits (8, 10, 11 or 12)
* @data_lane_shift: Data lane shifter
* 0 - CAMEXT[13:0] -> CAM[13:0]
* 1 - CAMEXT[13:2] -> CAM[11:0]
@@ -146,7 +145,6 @@ struct isp_reg {
* ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian
*/
struct isp_parallel_platform_data {
- unsigned int width;
unsigned int data_lane_shift:2;
unsigned int clk_pol:1;
unsigned int bridge:4;
@@ -262,6 +260,7 @@ struct isp_device {
/* ISP Obj */
spinlock_t stat_lock; /* common lock for statistic drivers */
struct mutex isp_mutex; /* For handling ref_count field */
+ bool needs_reset;
int has_context;
int ref_count;
unsigned int autoidle;
@@ -311,11 +310,12 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
enum isp_pipeline_stream_state state);
void omap3isp_configure_bridge(struct isp_device *isp,
enum ccdc_input_entity input,
- const struct isp_parallel_platform_data *pdata);
+ const struct isp_parallel_platform_data *pdata,
+ unsigned int shift);
-#define ISP_XCLK_NONE -1
-#define ISP_XCLK_A 0
-#define ISP_XCLK_B 1
+#define ISP_XCLK_NONE 0
+#define ISP_XCLK_A 1
+#define ISP_XCLK_B 2
struct isp_device *omap3isp_get(struct isp_device *isp);
void omap3isp_put(struct isp_device *isp);
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index 5ff9d14ce710..39d501bda636 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -43,6 +43,12 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
static const unsigned int ccdc_fmts[] = {
V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_Y12_1X12,
+ V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_SGBRG8_1X8,
V4L2_MBUS_FMT_SGRBG10_1X10,
V4L2_MBUS_FMT_SRGGB10_1X10,
V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -1110,21 +1116,38 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
struct isp_parallel_platform_data *pdata = NULL;
struct v4l2_subdev *sensor;
struct v4l2_mbus_framefmt *format;
+ const struct isp_format_info *fmt_info;
+ struct v4l2_subdev_format fmt_src;
+ unsigned int depth_out;
+ unsigned int depth_in = 0;
struct media_pad *pad;
unsigned long flags;
+ unsigned int shift;
u32 syn_mode;
u32 ccdc_pattern;
- if (ccdc->input == CCDC_INPUT_PARALLEL) {
- pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
- sensor = media_entity_to_v4l2_subdev(pad->entity);
+ pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
+ sensor = media_entity_to_v4l2_subdev(pad->entity);
+ if (ccdc->input == CCDC_INPUT_PARALLEL)
pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
->bus.parallel;
+
+ /* Compute shift value for lane shifter to configure the bridge. */
+ fmt_src.pad = pad->index;
+ fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {
+ fmt_info = omap3isp_video_format_info(fmt_src.format.code);
+ depth_in = fmt_info->bpp;
}
- omap3isp_configure_bridge(isp, ccdc->input, pdata);
+ fmt_info = omap3isp_video_format_info
+ (isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
+ depth_out = fmt_info->bpp;
+
+ shift = depth_in - depth_out;
+ omap3isp_configure_bridge(isp, ccdc->input, pdata, shift);
- ccdc->syncif.datsz = pdata ? pdata->width : 10;
+ ccdc->syncif.datsz = depth_out;
ccdc_config_sync_if(ccdc, &ccdc->syncif);
/* CCDC_PAD_SINK */
@@ -1338,7 +1361,7 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
* @ccdc: Pointer to ISP CCDC device.
* @event: Pointing which event trigger handler
*
- * Return 1 when the event and stopping request combination is satisfyied,
+ * Return 1 when the event and stopping request combination is satisfied,
* zero otherwise.
*/
static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
@@ -1618,7 +1641,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
ccdc_set_outaddr(ccdc, buffer->isp_addr);
- /* We now have a buffer queued on the output, restart the pipeline in
+ /* We now have a buffer queued on the output, restart the pipeline
* on the next CCDC interrupt if running in continuous mode (or when
* starting the stream).
*/
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
index d403af5d31d2..483a19cac1ad 100644
--- a/drivers/media/video/omap3isp/ispccdc.h
+++ b/drivers/media/video/omap3isp/ispccdc.h
@@ -150,7 +150,7 @@ struct ispccdc_lsc {
* @input: Active input
* @output: Active outputs
* @video_out: Output video node
- * @error: A hardware error occured during capture
+ * @error: A hardware error occurred during capture
* @alaw: A-law compression enabled (1) or disabled (0)
* @lpf: Low pass filter enabled (1) or disabled (0)
* @obclamp: Optical-black clamp enabled (1) or disabled (0)
@@ -163,7 +163,7 @@ struct ispccdc_lsc {
* @shadow_update: Controls update in progress by userspace
* @syncif: Interface synchronization configuration
* @vpcfg: Video port configuration
- * @underrun: A buffer underrun occured and a new buffer has been queued
+ * @underrun: A buffer underrun occurred and a new buffer has been queued
* @state: Streaming state
* @lock: Serializes shadow_update with interrupt handler
* @wait: Wait queue used to stop the module
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c
index 0efef2e78d93..0e16cab8e089 100644
--- a/drivers/media/video/omap3isp/ispccp2.c
+++ b/drivers/media/video/omap3isp/ispccp2.c
@@ -772,7 +772,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
* @sd : pointer to v4l2 subdev structure
* @fh : V4L2 subdev file handle
* @fmt : pointer to v4l2 subdev format structure
- * return -EINVAL or zero on sucess
+ * return -EINVAL or zero on success
*/
static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *fmt)
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c
index fb503f3db3be..69161a682b3d 100644
--- a/drivers/media/video/omap3isp/ispcsi2.c
+++ b/drivers/media/video/omap3isp/ispcsi2.c
@@ -969,7 +969,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
* @sd : pointer to v4l2 subdev structure
* @fh : V4L2 subdev file handle
* @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on sucess
+ * return -EINVAL or zero on success
*/
static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *fmt)
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c
index baf9374201dc..aba537af87e4 100644
--- a/drivers/media/video/omap3isp/isppreview.c
+++ b/drivers/media/video/omap3isp/isppreview.c
@@ -34,7 +34,7 @@
#include "ispreg.h"
#include "isppreview.h"
-/* Default values in Office Flourescent Light for RGBtoRGB Blending */
+/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
{ /* RGB-RGB Matrix */
{0x01E2, 0x0F30, 0x0FEE},
@@ -44,7 +44,7 @@ static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
{0x0000, 0x0000, 0x0000}
};
-/* Default values in Office Flourescent Light for RGB to YUV Conversion*/
+/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
static struct omap3isp_prev_csc flr_prev_csc = {
{ /* CSC Coef Matrix */
{66, 129, 25},
@@ -54,22 +54,22 @@ static struct omap3isp_prev_csc flr_prev_csc = {
{0x0, 0x0, 0x0}
};
-/* Default values in Office Flourescent Light for CFA Gradient*/
+/* Default values in Office Fluorescent Light for CFA Gradient*/
#define FLR_CFA_GRADTHRS_HORZ 0x28
#define FLR_CFA_GRADTHRS_VERT 0x28
-/* Default values in Office Flourescent Light for Chroma Suppression*/
+/* Default values in Office Fluorescent Light for Chroma Suppression*/
#define FLR_CSUP_GAIN 0x0D
#define FLR_CSUP_THRES 0xEB
-/* Default values in Office Flourescent Light for Noise Filter*/
+/* Default values in Office Fluorescent Light for Noise Filter*/
#define FLR_NF_STRGTH 0x03
/* Default values for White Balance */
#define FLR_WBAL_DGAIN 0x100
#define FLR_WBAL_COEF 0x20
-/* Default values in Office Flourescent Light for Black Adjustment*/
+/* Default values in Office Fluorescent Light for Black Adjustment*/
#define FLR_BLKADJ_BLUE 0x0
#define FLR_BLKADJ_GREEN 0x0
#define FLR_BLKADJ_RED 0x0
@@ -137,7 +137,7 @@ preview_enable_invalaw(struct isp_prev_device *prev, u8 enable)
* @enable: 1 - Enable, 0 - Disable
*
* NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also
- * The proccess is applied for each captured frame.
+ * The process is applied for each captured frame.
*/
static void
preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable)
@@ -157,7 +157,7 @@ preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable)
* @enable: 1 - Acquires memory bandwidth since the pixels in each frame is
* subtracted with the pixels in the current frame.
*
- * The proccess is applied for each captured frame.
+ * The process is applied for each captured frame.
*/
static void
preview_enable_drkframe(struct isp_prev_device *prev, u8 enable)
@@ -755,7 +755,7 @@ static struct preview_update update_attrs[] = {
* @configs - pointer to update config structure.
* @config - return pointer to appropriate structure field.
* @bit - for which feature to return pointers.
- * Return size of coresponding prev_params member
+ * Return size of corresponding prev_params member
*/
static u32
__preview_get_ptrs(struct prev_params *params, void **param,
@@ -1528,7 +1528,7 @@ static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
* preview_set_stream - Enable/Disable streaming on preview subdev
* @sd : pointer to v4l2 subdev structure
* @enable: 1 == Enable, 0 == Disable
- * return -EINVAL or zero on sucess
+ * return -EINVAL or zero on success
*/
static int preview_set_stream(struct v4l2_subdev *sd, int enable)
{
@@ -1780,7 +1780,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
* @sd : pointer to v4l2 subdev structure
* @fh : V4L2 subdev file handle
* @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on sucess
+ * return -EINVAL or zero on success
*/
static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *fmt)
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h
index f2d63ca4bd6f..fa943bd05c7f 100644
--- a/drivers/media/video/omap3isp/isppreview.h
+++ b/drivers/media/video/omap3isp/isppreview.h
@@ -163,7 +163,7 @@ struct isptables_update {
* @output: Bitmask of the active output
* @video_in: Input video entity
* @video_out: Output video entity
- * @error: A hardware error occured during capture
+ * @error: A hardware error occurred during capture
* @params: Module configuration data
* @shadow_update: If set, update the hardware configured in the next interrupt
* @underrun: Whether the preview entity has queued buffers on the output
diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c
index 8fddc5806b0d..9c317148205f 100644
--- a/drivers/media/video/omap3isp/ispqueue.c
+++ b/drivers/media/video/omap3isp/ispqueue.c
@@ -339,7 +339,7 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
up_read(&current->mm->mmap_sem);
if (ret != buf->npages) {
- buf->npages = ret;
+ buf->npages = ret < 0 ? 0 : ret;
isp_video_buffer_cleanup(buf);
return -EFAULT;
}
@@ -408,8 +408,8 @@ done:
* isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address
*
* This function locates the VMAs for the buffer's userspace address and checks
- * that their flags match. The onlflag that we need to care for at the moment is
- * VM_PFNMAP.
+ * that their flags match. The only flag that we need to care for at the moment
+ * is VM_PFNMAP.
*
* The buffer vm_flags field is set to the first VMA flags.
*
diff --git a/drivers/media/video/omap3isp/ispqueue.h b/drivers/media/video/omap3isp/ispqueue.h
index 251de3e1679d..92c5a12157d5 100644
--- a/drivers/media/video/omap3isp/ispqueue.h
+++ b/drivers/media/video/omap3isp/ispqueue.h
@@ -46,9 +46,9 @@ struct scatterlist;
* device yet.
* @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer.
* @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error
- * occured. For capture device the buffer likely contains corrupted data or
+ * occurred. For capture device the buffer likely contains corrupted data or
* no data at all.
- * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occured.
+ * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occurred.
* For capture devices the buffer contains valid data.
*/
enum isp_video_buffer_state {
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c
index 75d39b115d42..0bb0f8cd36f5 100644
--- a/drivers/media/video/omap3isp/ispresizer.c
+++ b/drivers/media/video/omap3isp/ispresizer.c
@@ -714,19 +714,50 @@ static void resizer_print_status(struct isp_res_device *res)
* iw and ih are the input width and height after cropping. Those equations need
* to be satisfied exactly for the resizer to work correctly.
*
- * Reverting the equations, we can compute the resizing ratios with
+ * The equations can't be easily reverted, as the >> 8 operation is not linear.
+ * In addition, not all input sizes can be achieved for a given output size. To
+ * get the highest input size lower than or equal to the requested input size,
+ * we need to compute the highest resizing ratio that satisfies the following
+ * inequality (taking the 4-tap mode width equation as an example)
+ *
+ * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
+ *
+ * (where iw is the requested input width) which can be rewritten as
+ *
+ * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
+ * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b
+ * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16
+ *
+ * where b is the value of the 8 least significant bits of the right hand side
+ * expression of the last inequality. The highest resizing ratio value will be
+ * achieved when b is equal to its maximum value of 255. That resizing ratio
+ * value will still satisfy the original inequality, as b will disappear when
+ * the expression will be shifted right by 8.
+ *
+ * The reverted the equations thus become
*
* - 8-phase, 4-tap mode
- * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1)
- * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1)
+ * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
+ * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
* - 4-phase, 7-tap mode
- * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1)
- * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1)
+ * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
+ * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
+ *
+ * The ratios are integer values, and are rounded down to ensure that the
+ * cropped input size is not bigger than the uncropped input size.
*
- * The ratios are integer values, and must be rounded down to ensure that the
- * cropped input size is not bigger than the uncropped input size. As the ratio
- * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the
- * 7-tap mode equations to compute a ratio approximation.
+ * As the number of phases/taps, used to select the correct equations to compute
+ * the ratio, depends on the ratio, we start with the 4-tap mode equations to
+ * compute an approximation of the ratio, and switch to the 7-tap mode equations
+ * if the approximation is higher than the ratio threshold.
+ *
+ * As the 7-tap mode equations will return a ratio smaller than or equal to the
+ * 4-tap mode equations, the resulting ratio could become lower than or equal to
+ * the ratio threshold. This 'equations loop' isn't an issue as long as the
+ * correct equations are used to compute the final input size. Starting with the
+ * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
+ * loop', the smallest of the ratio values will be used, never exceeding the
+ * requested input size.
*
* We first clamp the output size according to the hardware capabilitie to avoid
* auto-cropping the input more than required to satisfy the TRM equations. The
@@ -751,7 +782,7 @@ static void resizer_print_status(struct isp_res_device *res)
* ratio will thus result in a resizing factor slightly larger than the
* requested value.
*
- * To accomodate that, and make sure the TRM equations are satisfied exactly, we
+ * To accommodate that, and make sure the TRM equations are satisfied exactly, we
* compute the input crop rectangle as the last step.
*
* As if the situation wasn't complex enough, the maximum output width depends
@@ -775,6 +806,8 @@ static void resizer_calc_ratios(struct isp_res_device *res,
unsigned int max_width;
unsigned int max_height;
unsigned int width_alignment;
+ unsigned int width;
+ unsigned int height;
/*
* Clamp the output height based on the hardware capabilities and
@@ -786,19 +819,22 @@ static void resizer_calc_ratios(struct isp_res_device *res,
max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
output->height = clamp(output->height, min_height, max_height);
- ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv)
+ ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
/ (output->height - 1);
+ if (ratio->vert > MID_RESIZE_VALUE)
+ ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
+ / (output->height - 1);
ratio->vert = clamp_t(unsigned int, ratio->vert,
MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
if (ratio->vert <= MID_RESIZE_VALUE) {
upscaled_height = (output->height - 1) * ratio->vert
+ 32 * spv + 16;
- input->height = (upscaled_height >> 8) + 4;
+ height = (upscaled_height >> 8) + 4;
} else {
upscaled_height = (output->height - 1) * ratio->vert
+ 64 * spv + 32;
- input->height = (upscaled_height >> 8) + 7;
+ height = (upscaled_height >> 8) + 7;
}
/*
@@ -854,20 +890,29 @@ static void resizer_calc_ratios(struct isp_res_device *res,
max_width & ~(width_alignment - 1));
output->width = ALIGN(output->width, width_alignment);
- ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph)
+ ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
/ (output->width - 1);
+ if (ratio->horz > MID_RESIZE_VALUE)
+ ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
+ / (output->width - 1);
ratio->horz = clamp_t(unsigned int, ratio->horz,
MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
if (ratio->horz <= MID_RESIZE_VALUE) {
upscaled_width = (output->width - 1) * ratio->horz
+ 32 * sph + 16;
- input->width = (upscaled_width >> 8) + 7;
+ width = (upscaled_width >> 8) + 7;
} else {
upscaled_width = (output->width - 1) * ratio->horz
+ 64 * sph + 32;
- input->width = (upscaled_width >> 8) + 7;
+ width = (upscaled_width >> 8) + 7;
}
+
+ /* Center the new crop rectangle. */
+ input->left += (input->width - width) / 2;
+ input->top += (input->height - height) / 2;
+ input->width = width;
+ input->height = height;
}
/*
@@ -1386,7 +1431,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
* @sd : pointer to v4l2 subdev structure
* @fh : V4L2 subdev file handle
* @fmt : pointer to v4l2 subdev format structure
- * return -EINVAL or zero on sucess
+ * return -EINVAL or zero on success
*/
static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *fmt)
diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h
index 820950c9ef46..d86da94fa50d 100644
--- a/drivers/media/video/omap3isp/ispstat.h
+++ b/drivers/media/video/omap3isp/ispstat.h
@@ -131,9 +131,9 @@ struct ispstat {
struct ispstat_generic_config {
/*
* Fields must be in the same order as in:
- * - isph3a_aewb_config
- * - isph3a_af_config
- * - isphist_config
+ * - omap3isp_h3a_aewb_config
+ * - omap3isp_h3a_af_config
+ * - omap3isp_hist_config
*/
u32 buf_size;
u16 config_counter;
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
index a0bb5db9cb8a..9cd8f1aa567b 100644
--- a/drivers/media/video/omap3isp/ispvideo.c
+++ b/drivers/media/video/omap3isp/ispvideo.c
@@ -47,29 +47,59 @@
static struct isp_format_info formats[] = {
{ V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, },
+ V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_PIX_FMT_GREY, 8, },
+ { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_PIX_FMT_Y10, 10, },
+ { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_PIX_FMT_Y12, 12, },
+ { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_PIX_FMT_SBGGR8, 8, },
+ { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_PIX_FMT_SGBRG8, 8, },
+ { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_PIX_FMT_SGRBG8, 8, },
+ { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_PIX_FMT_SRGGB8, 8, },
{ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
+ V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+ V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
{ V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, },
+ V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_PIX_FMT_SBGGR10, 10, },
{ V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, },
+ V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_PIX_FMT_SGBRG10, 10, },
{ V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, },
+ V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_PIX_FMT_SGRBG10, 10, },
{ V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, },
+ V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_PIX_FMT_SRGGB10, 10, },
{ V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, },
+ V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_PIX_FMT_SBGGR12, 12, },
{ V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, },
+ V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_PIX_FMT_SGBRG12, 12, },
{ V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, },
+ V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_PIX_FMT_SGRBG12, 12, },
{ V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, },
+ V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_PIX_FMT_SRGGB12, 12, },
{ V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, },
+ V4L2_MBUS_FMT_UYVY8_1X16, 0,
+ V4L2_PIX_FMT_UYVY, 16, },
{ V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, },
+ V4L2_MBUS_FMT_YUYV8_1X16, 0,
+ V4L2_PIX_FMT_YUYV, 16, },
};
const struct isp_format_info *
@@ -86,6 +116,37 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
}
/*
+ * Decide whether desired output pixel code can be obtained with
+ * the lane shifter by shifting the input pixel code.
+ * @in: input pixelcode to shifter
+ * @out: output pixelcode from shifter
+ * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
+ *
+ * return true if the combination is possible
+ * return false otherwise
+ */
+static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in,
+ enum v4l2_mbus_pixelcode out,
+ unsigned int additional_shift)
+{
+ const struct isp_format_info *in_info, *out_info;
+
+ if (in == out)
+ return true;
+
+ in_info = omap3isp_video_format_info(in);
+ out_info = omap3isp_video_format_info(out);
+
+ if ((in_info->flavor == 0) || (out_info->flavor == 0))
+ return false;
+
+ if (in_info->flavor != out_info->flavor)
+ return false;
+
+ return in_info->bpp - out_info->bpp + additional_shift <= 6;
+}
+
+/*
* isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
* @video: ISP video instance
* @mbus: v4l2_mbus_framefmt format (input)
@@ -235,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
return -EPIPE;
while (1) {
+ unsigned int shifter_link;
/* Retrieve the sink format */
pad = &subdev->entity.pads[0];
if (!(pad->flags & MEDIA_PAD_FL_SINK))
@@ -263,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
return -ENOSPC;
}
+ /* If sink pad is on CCDC, the link has the lane shifter
+ * in the middle of it. */
+ shifter_link = subdev == &isp->isp_ccdc.subdev;
+
/* Retrieve the source format */
pad = media_entity_remote_source(pad);
if (pad == NULL ||
@@ -278,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
return -EPIPE;
/* Check if the two ends match */
- if (fmt_source.format.code != fmt_sink.format.code ||
- fmt_source.format.width != fmt_sink.format.width ||
+ if (fmt_source.format.width != fmt_sink.format.width ||
fmt_source.format.height != fmt_sink.format.height)
return -EPIPE;
+
+ if (shifter_link) {
+ unsigned int parallel_shift = 0;
+ if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) {
+ struct isp_parallel_platform_data *pdata =
+ &((struct isp_v4l2_subdevs_group *)
+ subdev->host_priv)->bus.parallel;
+ parallel_shift = pdata->data_lane_shift * 2;
+ }
+ if (!isp_video_is_shiftable(fmt_source.format.code,
+ fmt_sink.format.code,
+ parallel_shift))
+ return -EPIPE;
+ } else if (fmt_source.format.code != fmt_sink.format.code)
+ return -EPIPE;
}
return 0;
@@ -494,12 +574,12 @@ static const struct isp_video_queue_operations isp_video_queue_ops = {
/*
* omap3isp_video_buffer_next - Complete the current buffer and return the next
* @video: ISP video object
- * @error: Whether an error occured during capture
+ * @error: Whether an error occurred during capture
*
* Remove the current video buffer from the DMA queue and fill its timestamp,
* field count and state fields before waking up its completion handler.
*
- * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0)
+ * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0)
* or VIDEOBUF_ERROR otherwise (@error is non-zero).
*
* The DMA queue is expected to contain at least one buffer.
@@ -578,7 +658,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
/*
* omap3isp_video_resume - Perform resume operation on the buffers
* @video: ISP video object
- * @continuous: Pipeline is in single shot mode if 0 or continous mode otherwise
+ * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise
*
* This function is intended to be used on suspend/resume scenario. It
* requests video queue layer to discard buffers marked as DONE if it's in
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h
index 524a1acd0906..911bea64e78a 100644
--- a/drivers/media/video/omap3isp/ispvideo.h
+++ b/drivers/media/video/omap3isp/ispvideo.h
@@ -49,6 +49,8 @@ struct v4l2_pix_format;
* bits. Identical to @code if the format is 10 bits wide or less.
* @uncompressed: V4L2 media bus format code for the corresponding uncompressed
* format. Identical to @code if the format is not DPCM compressed.
+ * @flavor: V4L2 media bus format code for the same pixel layout but
+ * shifted to be 8 bits per pixel. =0 if format is not shiftable.
* @pixelformat: V4L2 pixel format FCC identifier
* @bpp: Bits per pixel
*/
@@ -56,6 +58,7 @@ struct isp_format_info {
enum v4l2_mbus_pixelcode code;
enum v4l2_mbus_pixelcode truncated;
enum v4l2_mbus_pixelcode uncompressed;
+ enum v4l2_mbus_pixelcode flavor;
u32 pixelformat;
unsigned int bpp;
};
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
index fe8e3ebd9ce4..456d9ad9ae5a 100644
--- a/drivers/media/video/ov6650.c
+++ b/drivers/media/video/ov6650.c
@@ -1038,7 +1038,7 @@ static int ov6650_reset(struct i2c_client *client)
ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0);
if (ret)
dev_err(&client->dev,
- "An error occured while entering soft reset!\n");
+ "An error occurred while entering soft reset!\n");
return ret;
}
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 53d88a2ab920..5173ac449dd8 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -273,7 +273,7 @@ static int ov9640_reset(struct i2c_client *client)
ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
if (ret)
dev_err(&client->dev,
- "An error occured while entering soft reset!\n");
+ "An error occurred while entering soft reset!\n");
return ret;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index aeed1c2945fb..9515f3a68f8f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -32,7 +32,7 @@
Read and analyze data in the eeprom. Use tveeprom to figure out
the packet structure, since this is another Hauppauge device and
- internally it has a family resemblence to ivtv-type devices
+ internally it has a family resemblance to ivtv-type devices
*/
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 51d3009ab57f..d7753ae9ff46 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -75,7 +75,7 @@ enum pvr2_v4l_type {
* (but it might still on the bus). In this state there's nothing we can
* do; it must be replugged in order to recover.
*
- * COLD - Device is in an unusuable state, needs microcontroller firmware.
+ * COLD - Device is in an unusable state, needs microcontroller firmware.
*
* WARM - We can communicate with the device and the proper
* microcontroller firmware is running, but other device initialization is
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index ca9f83a85ca5..453627b07833 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -278,12 +278,10 @@ static struct v4l2_standard generic_standards[] = {
}
};
-#define generic_standards_cnt ARRAY_SIZE(generic_standards)
-
static struct v4l2_standard *match_std(v4l2_std_id id)
{
unsigned int idx;
- for (idx = 0; idx < generic_standards_cnt; idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) {
if (generic_standards[idx].id & id) {
return generic_standards + idx;
}
@@ -370,7 +368,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt,
GFP_KERNEL);
- for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
+ if (!stddefs)
+ return NULL;
+
+ for (idx = 0; idx < std_cnt; idx++)
+ stddefs[idx].index = idx;
idx = 0;
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 780af5f81642..356cd42b593b 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1850,7 +1850,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
} else {
/* Device is closed, so we can safely unregister it */
PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
- pwc_cleanup(pdev);
disconnect_out:
/* search device_hint[] table if we occupy a slot, by any chance */
@@ -1860,6 +1859,7 @@ disconnect_out:
}
mutex_unlock(&pdev->modlock);
+ pwc_cleanup(pdev);
}
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index aa87e462a958..f85c51249c7b 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -379,8 +379,27 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
{
- int i;
-
+ int i, idx;
+ u32 id;
+
+ id = c->id;
+ if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+ id &= V4L2_CTRL_ID_MASK;
+ id++;
+ idx = -1;
+ for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) {
+ if (pwc_controls[i].id < id)
+ continue;
+ if (idx >= 0
+ && pwc_controls[i].id > pwc_controls[idx].id)
+ continue;
+ idx = i;
+ }
+ if (idx < 0)
+ return -EINVAL;
+ memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]);
+ return 0;
+ }
for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
if (pwc_controls[i].id == c->id) {
PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 02686771740d..b42bfa5ccdf2 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -714,7 +714,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
*
* The DMA chaining is done with DMA running. This means a tiny temporal window
* remains, where a buffer is queued on the chain, while the chain is already
- * stopped. This means the tailed buffer would never be transfered by DMA.
+ * stopped. This means the tailed buffer would never be transferred by DMA.
* This function restarts the capture for this corner case, where :
* - DADR() == DADDR_STOP
* - a videobuffer is queued on the pcdev->capture list
@@ -1155,15 +1155,11 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long bus_flags, camera_flags, common_flags;
- const struct soc_mbus_pixelfmt *fmt;
int ret;
struct pxa_cam *cam = icd->host_priv;
- fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
- if (!fmt)
- return -EINVAL;
-
- ret = test_platform_param(pcdev, fmt->bits_per_sample, &bus_flags);
+ ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample,
+ &bus_flags);
if (ret < 0)
return ret;
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 561909b65ce6..5b9dce85645c 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -394,12 +394,17 @@ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
/* start video number */
static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
+/* Enable jpeg capture. */
+static int jpeg_enable = 1;
+
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
module_param(vid_limit, int, 0644);
MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
module_param(video_nr, int, 0644);
MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
+module_param(jpeg_enable, int, 0644);
+MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1");
/* USB device table */
#define USB_SENSORAY_VID 0x1943
@@ -413,6 +418,7 @@ MODULE_DEVICE_TABLE(usb, s2255_table);
#define BUFFER_TIMEOUT msecs_to_jiffies(400)
/* image formats. */
+/* JPEG formats must be defined last to support jpeg_enable parameter */
static const struct s2255_fmt formats[] = {
{
.name = "4:2:2, planar, YUV422P",
@@ -429,13 +435,17 @@ static const struct s2255_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16
}, {
+ .name = "8bpp GREY",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = 8
+ }, {
.name = "JPG",
.fourcc = V4L2_PIX_FMT_JPEG,
.depth = 24
}, {
- .name = "8bpp GREY",
- .fourcc = V4L2_PIX_FMT_GREY,
- .depth = 8
+ .name = "MJPG",
+ .fourcc = V4L2_PIX_FMT_MJPEG,
+ .depth = 24
}
};
@@ -610,6 +620,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (-1 == formats[i].fourcc)
continue;
+ if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
+ continue;
if (formats[i].fourcc == fourcc)
return formats + i;
}
@@ -653,6 +666,7 @@ static void s2255_fillbuff(struct s2255_channel *channel,
memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
break;
case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_MJPEG:
buf->vb.size = jpgsize;
memcpy(vbuf, tmpbuf, buf->vb.size);
break;
@@ -856,7 +870,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (index >= ARRAY_SIZE(formats))
return -EINVAL;
-
+ if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
+ return -EINVAL;
dprintk(4, "name %s\n", formats[index].name);
strlcpy(f->description, formats[index].name, sizeof(f->description));
f->pixelformat = formats[index].fourcc;
@@ -1037,6 +1053,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
mode.color |= COLOR_Y8;
break;
case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_MJPEG:
mode.color &= ~MASK_COLOR;
mode.color |= COLOR_JPG;
mode.color |= (channel->jc.quality << 8);
@@ -2382,7 +2399,7 @@ static void read_pipe_completion(struct urb *purb)
read_pipe_completion, pipe_info);
if (pipe_info->state != 0) {
- if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
dev_err(&dev->udev->dev, "error submitting urb\n");
}
} else {
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
index 7ea1b1403b1e..df6954ab1d99 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -1,3 +1,5 @@
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o
+s5p-csis-objs := mipi-csis.o
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
-s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
+obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 95f8b4e11e46..d142b40ea64e 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -527,7 +527,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
if (ret)
return ret;
- if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
+ if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
return -EBUSY;
frame = &ctx->d_frame;
@@ -539,8 +539,10 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
return -EINVAL;
}
- for (i = 0; i < frame->fmt->colplanes; i++)
- frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height;
+ for (i = 0; i < frame->fmt->colplanes; i++) {
+ frame->payload[i] =
+ (pix->width * pix->height * frame->fmt->depth[i]) >> 3;
+ }
/* Output DMA frame pixel size and offsets. */
frame->f_width = pix->plane_fmt[0].bytesperline * 8
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 6c919b38a3d8..dc91a8511af6 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -361,10 +361,20 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc)
{
struct fimc_vid_cap *cap = &fimc->vid_cap;
struct fimc_vid_buffer *v_buf;
+ struct timeval *tv;
+ struct timespec ts;
if (!list_empty(&cap->active_buf_q) &&
test_bit(ST_CAPT_RUN, &fimc->state)) {
+ ktime_get_real_ts(&ts);
+
v_buf = active_queue_pop(cap);
+
+ tv = &v_buf->vb.v4l2_buf.timestamp;
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ v_buf->vb.v4l2_buf.sequence = cap->frame_count++;
+
vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
}
@@ -758,7 +768,7 @@ static void fimc_unlock(struct vb2_queue *vq)
mutex_unlock(&ctx->fimc_dev->lock);
}
-struct vb2_ops fimc_qops = {
+static struct vb2_ops fimc_qops = {
.queue_setup = fimc_queue_setup,
.buf_prepare = fimc_buf_prepare,
.buf_queue = fimc_buf_queue,
@@ -927,23 +937,23 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv,
pix->num_planes = fmt->memplanes;
pix->colorspace = V4L2_COLORSPACE_JPEG;
- for (i = 0; i < pix->num_planes; ++i) {
- int bpl = pix->plane_fmt[i].bytesperline;
- dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d",
- i, bpl, fmt->depth[i], pix->width, pix->height);
+ for (i = 0; i < pix->num_planes; ++i) {
+ u32 bpl = pix->plane_fmt[i].bytesperline;
+ u32 *sizeimage = &pix->plane_fmt[i].sizeimage;
- if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width)
- bpl = (pix->width * fmt->depth[0]) >> 3;
+ if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
+ bpl = pix->width; /* Planar */
- if (!pix->plane_fmt[i].sizeimage)
- pix->plane_fmt[i].sizeimage = pix->height * bpl;
+ if (fmt->colplanes == 1 && /* Packed */
+ (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
+ bpl = (pix->width * fmt->depth[0]) / 8;
- pix->plane_fmt[i].bytesperline = bpl;
+ if (i == 0) /* Same bytesperline for each plane. */
+ mod_x = bpl;
- dbg("[%d]: bpl: %d, sizeimage: %d",
- i, pix->plane_fmt[i].bytesperline,
- pix->plane_fmt[i].sizeimage);
+ pix->plane_fmt[i].bytesperline = mod_x;
+ *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8;
}
return 0;
@@ -965,7 +975,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
- if (vb2_is_streaming(vq)) {
+ if (vb2_is_busy(vq)) {
v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type);
return -EBUSY;
}
@@ -985,8 +995,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
if (!frame->fmt)
return -EINVAL;
- for (i = 0; i < frame->fmt->colplanes; i++)
- frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height;
+ for (i = 0; i < frame->fmt->colplanes; i++) {
+ frame->payload[i] =
+ (pix->width * pix->height * frame->fmt->depth[i]) / 8;
+ }
frame->f_width = pix->plane_fmt[0].bytesperline * 8 /
frame->fmt->depth[0];
@@ -1750,7 +1762,7 @@ static int __devexit fimc_remove(struct platform_device *pdev)
}
/* Image pixel limits, similar across several FIMC HW revisions. */
-static struct fimc_pix_limit s5p_pix_limit[3] = {
+static struct fimc_pix_limit s5p_pix_limit[4] = {
[0] = {
.scaler_en_w = 3264,
.scaler_dis_w = 8192,
@@ -1775,6 +1787,14 @@ static struct fimc_pix_limit s5p_pix_limit[3] = {
.out_rot_en_w = 1280,
.out_rot_dis_w = 1920,
},
+ [3] = {
+ .scaler_en_w = 1920,
+ .scaler_dis_w = 8192,
+ .in_rot_en_h = 1366,
+ .in_rot_dis_w = 8192,
+ .out_rot_en_w = 1366,
+ .out_rot_dis_w = 1920,
+ },
};
static struct samsung_fimc_variant fimc0_variant_s5p = {
@@ -1827,7 +1847,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
.pix_limit = &s5p_pix_limit[2],
};
-static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
+static struct samsung_fimc_variant fimc0_variant_exynos4 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
@@ -1840,7 +1860,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
.pix_limit = &s5p_pix_limit[1],
};
-static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
+static struct samsung_fimc_variant fimc2_variant_exynos4 = {
.pix_hoff = 1,
.has_cistatus2 = 1,
.has_mainscaler_ext = 1,
@@ -1848,7 +1868,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
.min_out_pixsize = 16,
.hor_offs_align = 1,
.out_buf_count = 32,
- .pix_limit = &s5p_pix_limit[2],
+ .pix_limit = &s5p_pix_limit[3],
};
/* S5PC100 */
@@ -1874,12 +1894,12 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
};
/* S5PV310, S5PC210 */
-static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = {
+static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = {
.variant = {
- [0] = &fimc0_variant_s5pv310,
- [1] = &fimc0_variant_s5pv310,
- [2] = &fimc0_variant_s5pv310,
- [3] = &fimc2_variant_s5pv310,
+ [0] = &fimc0_variant_exynos4,
+ [1] = &fimc0_variant_exynos4,
+ [2] = &fimc0_variant_exynos4,
+ [3] = &fimc2_variant_exynos4,
},
.num_entities = 4,
.lclk_frequency = 166000000UL,
@@ -1893,8 +1913,8 @@ static struct platform_device_id fimc_driver_ids[] = {
.name = "s5pv210-fimc",
.driver_data = (unsigned long)&fimc_drvdata_s5pv210,
}, {
- .name = "s5pv310-fimc",
- .driver_data = (unsigned long)&fimc_drvdata_s5pv310,
+ .name = "exynos4-fimc",
+ .driver_data = (unsigned long)&fimc_drvdata_exynos4,
},
{},
};
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 4d929a394521..4893b2d91d84 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -356,7 +356,7 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx)
/* one shot mode */
cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
} else {
- /* Continous frame capture mode (freerun). */
+ /* Continuous frame capture mode (freerun). */
cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
S5P_CIIMGCPT_CPT_FRMOD_CNT);
cfg |= S5P_CIIMGCPT_IMGCPTEN;
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
new file mode 100644
index 000000000000..ef056d6605ca
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/mipi-csis.c
@@ -0,0 +1,724 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <plat/mipi_csis.h>
+#include "mipi-csis.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* Register map definition */
+
+/* CSIS global control */
+#define S5PCSIS_CTRL 0x00
+#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31)
+#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8)
+#define S5PCSIS_CTRL_RESET (1 << 4)
+#define S5PCSIS_CTRL_ENABLE (1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL 0x04
+#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27)
+#define S5PCSIS_DPHYCTRL_ENABLE (0x1f << 0)
+
+#define S5PCSIS_CONFIG 0x08
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK (0x3f << 2)
+#define S5PCSIS_CFG_NR_LANE_MASK 3
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK 0x10
+#define S5PCSIS_INTMSK_EN_ALL 0xf000003f
+#define S5PCSIS_INTSRC 0x14
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL 0x2c
+#define CSIS_MAX_PIX_WIDTH 0xffff
+#define CSIS_MAX_PIX_HEIGHT 0xffff
+
+enum {
+ CSIS_CLK_MUX,
+ CSIS_CLK_GATE,
+};
+
+static char *csi_clock_name[] = {
+ [CSIS_CLK_MUX] = "sclk_csis",
+ [CSIS_CLK_GATE] = "csis",
+};
+#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
+
+enum {
+ ST_POWERED = 1,
+ ST_STREAMING = 2,
+ ST_SUSPENDED = 4,
+};
+
+/**
+ * struct csis_state - the driver's internal state data structure
+ * @lock: mutex serializing the subdev and power management operations,
+ * protecting @format and @flags members
+ * @pads: CSIS pads array
+ * @sd: v4l2_subdev associated with CSIS device instance
+ * @pdev: CSIS platform device
+ * @regs_res: requested I/O register memory resource
+ * @regs: mmaped I/O registers memory
+ * @clock: CSIS clocks
+ * @irq: requested s5p-mipi-csis irq number
+ * @flags: the state variable for power and streaming control
+ * @csis_fmt: current CSIS pixel format
+ * @format: common media bus format for the source and sink pad
+ */
+struct csis_state {
+ struct mutex lock;
+ struct media_pad pads[CSIS_PADS_NUM];
+ struct v4l2_subdev sd;
+ struct platform_device *pdev;
+ struct resource *regs_res;
+ void __iomem *regs;
+ struct clk *clock[NUM_CSIS_CLOCKS];
+ int irq;
+ struct regulator *supply;
+ u32 flags;
+ const struct csis_pix_format *csis_fmt;
+ struct v4l2_mbus_framefmt format;
+};
+
+/**
+ * struct csis_pix_format - CSIS pixel format description
+ * @pix_width_alignment: horizontal pixel alignment, width will be
+ * multiple of 2^pix_width_alignment
+ * @code: corresponding media bus code
+ * @fmt_reg: S5PCSIS_CONFIG register value
+ */
+struct csis_pix_format {
+ unsigned int pix_width_alignment;
+ enum v4l2_mbus_pixelcode code;
+ u32 fmt_reg;
+};
+
+static const struct csis_pix_format s5pcsis_formats[] = {
+ {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
+ }, {
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
+ },
+};
+
+#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
+
+static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct csis_state, sd);
+}
+
+static const struct csis_pix_format *find_csis_format(
+ struct v4l2_mbus_framefmt *mf)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++)
+ if (mf->code == s5pcsis_formats[i].code)
+ return &s5pcsis_formats[i];
+ return NULL;
+}
+
+static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
+
+ val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+ val & ~S5PCSIS_INTMSK_EN_ALL;
+ s5pcsis_write(state, S5PCSIS_INTMSK, val);
+}
+
+static void s5pcsis_reset(struct csis_state *state)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
+
+ s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
+ udelay(10);
+}
+
+static void s5pcsis_system_enable(struct csis_state *state, int on)
+{
+ u32 val;
+
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ if (on)
+ val |= S5PCSIS_CTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_CTRL_ENABLE;
+ s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+ val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+ if (on)
+ val |= S5PCSIS_DPHYCTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+ s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(struct csis_state *state)
+{
+ struct v4l2_mbus_framefmt *mf = &state->format;
+ u32 val;
+
+ v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n",
+ mf->code, mf->width, mf->height);
+
+ /* Color format */
+ val = s5pcsis_read(state, S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+ s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+ /* Pixel resolution */
+ val = (mf->width << 16) | mf->height;
+ s5pcsis_write(state, S5PCSIS_RESOL, val);
+}
+
+static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+
+ val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27);
+ s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+static void s5pcsis_set_params(struct csis_state *state)
+{
+ struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
+ u32 val;
+
+ val = s5pcsis_read(state, S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
+ s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+ __s5pcsis_set_format(state);
+ s5pcsis_set_hsync_settle(state, pdata->hs_settle);
+
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ if (pdata->alignment == 32)
+ val |= S5PCSIS_CTRL_ALIGN_32BIT;
+ else /* 24-bits */
+ val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+ /* Not using external clock. */
+ val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
+ s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+ /* Update the shadow register. */
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
+}
+
+static void s5pcsis_clk_put(struct csis_state *state)
+{
+ int i;
+
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++)
+ if (!IS_ERR_OR_NULL(state->clock[i]))
+ clk_put(state->clock[i]);
+}
+
+static int s5pcsis_clk_get(struct csis_state *state)
+{
+ struct device *dev = &state->pdev->dev;
+ int i;
+
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+ state->clock[i] = clk_get(dev, csi_clock_name[i]);
+ if (IS_ERR(state->clock[i])) {
+ s5pcsis_clk_put(state);
+ dev_err(dev, "failed to get clock: %s\n",
+ csi_clock_name[i]);
+ return -ENXIO;
+ }
+ }
+ return 0;
+}
+
+static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct device *dev = &state->pdev->dev;
+
+ if (on)
+ return pm_runtime_get_sync(dev);
+
+ return pm_runtime_put_sync(dev);
+}
+
+static void s5pcsis_start_stream(struct csis_state *state)
+{
+ s5pcsis_reset(state);
+ s5pcsis_set_params(state);
+ s5pcsis_system_enable(state, true);
+ s5pcsis_enable_interrupts(state, true);
+}
+
+static void s5pcsis_stop_stream(struct csis_state *state)
+{
+ s5pcsis_enable_interrupts(state, false);
+ s5pcsis_system_enable(state, false);
+}
+
+/* v4l2_subdev operations */
+static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n",
+ __func__, enable, state->flags);
+
+ if (enable) {
+ ret = pm_runtime_get_sync(&state->pdev->dev);
+ if (ret && ret != 1)
+ return ret;
+ }
+ mutex_lock(&state->lock);
+ if (enable) {
+ if (state->flags & ST_SUSPENDED) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+ s5pcsis_start_stream(state);
+ state->flags |= ST_STREAMING;
+ } else {
+ s5pcsis_stop_stream(state);
+ state->flags &= ~ST_STREAMING;
+ }
+unlock:
+ mutex_unlock(&state->lock);
+ if (!enable)
+ pm_runtime_put(&state->pdev->dev);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(s5pcsis_formats))
+ return -EINVAL;
+
+ code->code = s5pcsis_formats[code->index].code;
+ return 0;
+}
+
+static struct csis_pix_format const *s5pcsis_try_format(
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct csis_pix_format const *csis_fmt;
+
+ csis_fmt = find_csis_format(mf);
+ if (csis_fmt == NULL)
+ csis_fmt = &s5pcsis_formats[0];
+
+ mf->code = csis_fmt->code;
+ v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+ csis_fmt->pix_width_alignment,
+ &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+ 0);
+ return csis_fmt;
+}
+
+static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
+ struct csis_state *state, struct v4l2_subdev_fh *fh,
+ u32 pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+
+ return &state->format;
+}
+
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct csis_pix_format const *csis_fmt;
+ struct v4l2_mbus_framefmt *mf;
+
+ if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+ return -EINVAL;
+
+ mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+
+ if (fmt->pad == CSIS_PAD_SOURCE) {
+ if (mf) {
+ mutex_lock(&state->lock);
+ fmt->format = *mf;
+ mutex_unlock(&state->lock);
+ }
+ return 0;
+ }
+ csis_fmt = s5pcsis_try_format(&fmt->format);
+ if (mf) {
+ mutex_lock(&state->lock);
+ *mf = fmt->format;
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ state->csis_fmt = csis_fmt;
+ mutex_unlock(&state->lock);
+ }
+ return 0;
+}
+
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+ return -EINVAL;
+
+ mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+ if (!mf)
+ return -EINVAL;
+
+ mutex_lock(&state->lock);
+ fmt->format = *mf;
+ mutex_unlock(&state->lock);
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
+ .s_power = s5pcsis_s_power,
+};
+
+static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
+ .enum_mbus_code = s5pcsis_enum_mbus_code,
+ .get_fmt = s5pcsis_get_fmt,
+ .set_fmt = s5pcsis_set_fmt,
+};
+
+static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
+ .s_stream = s5pcsis_s_stream,
+};
+
+static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
+ .core = &s5pcsis_core_ops,
+ .pad = &s5pcsis_pad_ops,
+ .video = &s5pcsis_video_ops,
+};
+
+static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
+{
+ struct csis_state *state = dev_id;
+ u32 val;
+
+ /* Just clear the interrupt pending bits. */
+ val = s5pcsis_read(state, S5PCSIS_INTSRC);
+ s5pcsis_write(state, S5PCSIS_INTSRC, val);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit s5pcsis_probe(struct platform_device *pdev)
+{
+ struct s5p_platform_mipi_csis *pdata;
+ struct resource *mem_res;
+ struct resource *regs_res;
+ struct csis_state *state;
+ int ret = -ENOMEM;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ mutex_init(&state->lock);
+ state->pdev = pdev;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL || pdata->phy_enable == NULL) {
+ dev_err(&pdev->dev, "Platform data not fully specified\n");
+ goto e_free;
+ }
+
+ if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
+ pdata->lanes > CSIS0_MAX_LANES) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
+ pdata->lanes);
+ goto e_free;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get IO memory region\n");
+ goto e_free;
+ }
+
+ regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+ pdev->name);
+ if (!regs_res) {
+ dev_err(&pdev->dev, "Failed to request IO memory region\n");
+ goto e_free;
+ }
+ state->regs_res = regs_res;
+
+ state->regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (!state->regs) {
+ dev_err(&pdev->dev, "Failed to remap IO region\n");
+ goto e_reqmem;
+ }
+
+ ret = s5pcsis_clk_get(state);
+ if (ret)
+ goto e_unmap;
+
+ clk_enable(state->clock[CSIS_CLK_MUX]);
+ if (pdata->clk_rate)
+ clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+ else
+ dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+
+ state->irq = platform_get_irq(pdev, 0);
+ if (state->irq < 0) {
+ ret = state->irq;
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ goto e_clkput;
+ }
+
+ if (!pdata->fixed_phy_vdd) {
+ state->supply = regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(state->supply)) {
+ ret = PTR_ERR(state->supply);
+ state->supply = NULL;
+ goto e_clkput;
+ }
+ }
+
+ ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
+ dev_name(&pdev->dev), state);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto e_regput;
+ }
+
+ v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
+ state->sd.owner = THIS_MODULE;
+ strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
+ state->csis_fmt = &s5pcsis_formats[0];
+
+ state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&state->sd.entity,
+ CSIS_PADS_NUM, state->pads, 0);
+ if (ret < 0)
+ goto e_irqfree;
+
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&state->sd, pdev);
+
+ /* .. and a pointer to the subdev. */
+ platform_set_drvdata(pdev, &state->sd);
+
+ state->flags = ST_SUSPENDED;
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+e_irqfree:
+ free_irq(state->irq, state);
+e_regput:
+ if (state->supply)
+ regulator_put(state->supply);
+e_clkput:
+ clk_disable(state->clock[CSIS_CLK_MUX]);
+ s5pcsis_clk_put(state);
+e_unmap:
+ iounmap(state->regs);
+e_reqmem:
+ release_mem_region(regs_res->start, resource_size(regs_res));
+e_free:
+ kfree(state);
+ return ret;
+}
+
+static int s5pcsis_suspend(struct device *dev)
+{
+ struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+ __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (state->flags & ST_POWERED) {
+ s5pcsis_stop_stream(state);
+ ret = pdata->phy_enable(state->pdev, false);
+ if (ret)
+ goto unlock;
+ if (state->supply) {
+ ret = regulator_disable(state->supply);
+ if (ret)
+ goto unlock;
+ }
+ clk_disable(state->clock[CSIS_CLK_GATE]);
+ state->flags &= ~ST_POWERED;
+ }
+ state->flags |= ST_SUSPENDED;
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+static int s5pcsis_resume(struct device *dev)
+{
+ struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+ __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (!(state->flags & ST_SUSPENDED))
+ goto unlock;
+
+ if (!(state->flags & ST_POWERED)) {
+ if (state->supply)
+ ret = regulator_enable(state->supply);
+ if (ret)
+ goto unlock;
+
+ ret = pdata->phy_enable(state->pdev, true);
+ if (!ret) {
+ state->flags |= ST_POWERED;
+ } else if (state->supply) {
+ regulator_disable(state->supply);
+ goto unlock;
+ }
+ clk_enable(state->clock[CSIS_CLK_GATE]);
+ }
+ if (state->flags & ST_STREAMING)
+ s5pcsis_start_stream(state);
+
+ state->flags &= ~ST_SUSPENDED;
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s5pcsis_pm_suspend(struct device *dev)
+{
+ return s5pcsis_suspend(dev);
+}
+
+static int s5pcsis_pm_resume(struct device *dev)
+{
+ int ret;
+
+ ret = s5pcsis_resume(dev);
+
+ if (!ret) {
+ pm_runtime_disable(dev);
+ ret = pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+
+ return ret;
+}
+#endif
+
+static int __devexit s5pcsis_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct resource *res = state->regs_res;
+
+ pm_runtime_disable(&pdev->dev);
+ s5pcsis_suspend(&pdev->dev);
+ clk_disable(state->clock[CSIS_CLK_MUX]);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ s5pcsis_clk_put(state);
+ if (state->supply)
+ regulator_put(state->supply);
+
+ media_entity_cleanup(&state->sd.entity);
+ free_irq(state->irq, state);
+ iounmap(state->regs);
+ release_mem_region(res->start, resource_size(res));
+ kfree(state);
+
+ return 0;
+}
+
+static const struct dev_pm_ops s5pcsis_pm_ops = {
+ SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume)
+};
+
+static struct platform_driver s5pcsis_driver = {
+ .probe = s5pcsis_probe,
+ .remove = __devexit_p(s5pcsis_remove),
+ .driver = {
+ .name = CSIS_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &s5pcsis_pm_ops,
+ },
+};
+
+static int __init s5pcsis_init(void)
+{
+ return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe);
+}
+
+static void __exit s5pcsis_exit(void)
+{
+ platform_driver_unregister(&s5pcsis_driver);
+}
+
+module_init(s5pcsis_init);
+module_exit(s5pcsis_exit);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h
new file mode 100644
index 000000000000..f5691336dd5c
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/mipi-csis.h
@@ -0,0 +1,22 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef S5P_MIPI_CSIS_H_
+#define S5P_MIPI_CSIS_H_
+
+#define CSIS_DRIVER_NAME "s5p-mipi-csis"
+#define CSIS_MAX_ENTITIES 2
+#define CSIS0_MAX_LANES 4
+#define CSIS1_MAX_LANES 2
+
+#define CSIS_PAD_SINK 0
+#define CSIS_PAD_SOURCE 1
+#define CSIS_PADS_NUM 2
+
+#endif
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 61c6007c8ea6..e2062b240e32 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5591,6 +5591,105 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
},
},
+ [SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2] = {
+ /* Timothy Lee <timothy.lee@siriushk.com> */
+ .name = "MagicPro ProHDTV Pro2 DMB-TH/Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_config = 3,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x02050000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x00050000,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00050000,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00050000,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x00050000,
+ },
+ .mute = {
+ .name = name_mute,
+ .vmux = 0,
+ .amux = TV,
+ .gpio = 0x00050000,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_501] = {
+ /* Beholder Intl. Ltd. 2010 */
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 501",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 3,
+ .amux = LINE2,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_503FM] = {
+ /* Beholder Intl. Ltd. 2010 */
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 503 FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 3,
+ .amux = LINE2,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
};
@@ -6796,6 +6895,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0xc900,
.driver_data = SAA7134_BOARD_VIDEOMATE_M1F,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5030,
+ .driver_data = SAA7134_BOARD_BEHOLD_503FM,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5010,
+ .driver_data = SAA7134_BOARD_BEHOLD_501,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x17de,
+ .subdevice = 0xd136,
+ .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -6988,6 +7105,7 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
switch (dev->board) {
case SAA7134_BOARD_HAUPPAUGE_HVR1150:
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
break;
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
@@ -7014,6 +7132,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
case SAA7134_BOARD_AVERMEDIA_M733A:
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
/* tda8290 + tda18271 */
ret = saa7134_tda8290_18271_callback(dev, command, arg);
break;
@@ -7264,6 +7383,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_HAUPPAUGE_HVR1150:
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
/* GPIO 26 high for digital, low for analog */
saa7134_set_gpio(dev, 26, 0);
msleep(1);
@@ -7326,6 +7446,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa7134_set_gpio(dev, 1, 1);
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ /* enable LGS-8G75 */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0e050000, 0x0c050000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000);
+ break;
}
return 0;
}
@@ -7460,7 +7585,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
break;
default:
- printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t);
+ printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t);
}
} else if ((data[1] != 0) && (data[1] != 0xff)) {
/* new config structure */
@@ -7480,7 +7605,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
printk(KERN_INFO "%s Board has DVB-T\n", dev->name);
break;
default:
- printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t);
+ printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t);
}
} else {
printk(KERN_ERR "%s unexpected config structure\n", dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 41f836fc93ec..f9be737ba6f4 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -927,7 +927,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
}
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index f65cad287b83..996a206c6d79 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -53,6 +53,7 @@
#include "lgdt3305.h"
#include "tda8290.h"
#include "mb86a20s.h"
+#include "lgs8gxx.h"
#include "zl10353.h"
@@ -1123,6 +1124,26 @@ static struct tda18271_config dtv1000s_tda18271_config = {
.gate = TDA18271_GATE_ANALOG,
};
+static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = {
+ .prod = LGS8GXX_PROD_LGS8G75,
+ .demod_address = 0x1d,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 0,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 4000, /* 4.00 MHz */
+ .if_neg_center = 0,
+ .ext_adc = 0,
+ .adc_signed = 1,
+ .adc_vpp = 3, /* 2.0 Vpp */
+ .if_neg_edge = 1,
+};
+
+static struct tda18271_config prohdtv_pro2_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
/* ==================================================================
* Core code
*/
@@ -1674,6 +1695,19 @@ static int dvb_init(struct saa7134_dev *dev)
/* mb86a20s need to use the I2C gateway */
break;
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &prohdtv_pro2_lgs8g75_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ 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,
+ &prohdtv_pro2_tda18271_config);
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index be1c2a2de27c..ff6c0e97563e 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -756,6 +756,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0x0ff00;
mask_keyup = 0x040000;
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ ir_codes = RC_MAP_HAUPPAUGE;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index f96cd5d761f9..28eb10398323 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -328,6 +328,9 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
#define SAA7134_BOARD_VIDEOMATE_M1F 183
#define SAA7134_BOARD_ENCORE_ENLTV_FM3 184
+#define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185
+#define SAA7134_BOARD_BEHOLD_501 186
+#define SAA7134_BOARD_BEHOLD_503FM 187
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/video/saa7164/saa7164-cmd.c
index 6a4c217ed3a7..62fac7f9d04e 100644
--- a/drivers/media/video/saa7164/saa7164-cmd.c
+++ b/drivers/media/video/saa7164/saa7164-cmd.c
@@ -257,7 +257,7 @@ out:
}
/* Wait for a signal event, without holding a mutex. Either return TIMEOUT if
- * the event never occured, or SAA_OK if it was signaled during the wait.
+ * the event never occurred, or SAA_OK if it was signaled during the wait.
*/
int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno)
{
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
index b813aec1e456..3b7d7b4e3034 100644
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ b/drivers/media/video/saa7164/saa7164-core.c
@@ -1247,7 +1247,7 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
}
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
index f9d594698832..400364569c8d 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -177,7 +177,7 @@ static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
}
}
- /* Allocate some kenrel kernel buffers for copying
+ /* Allocate some kernel buffers for copying
* to userpsace.
*/
len = params->numberoflines * params->pitch;
diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/video/saa7164/saa7164-fw.c
index b369300cce06..a266bf0169e6 100644
--- a/drivers/media/video/saa7164/saa7164-fw.c
+++ b/drivers/media/video/saa7164/saa7164-fw.c
@@ -444,7 +444,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
printk(KERN_INFO " .Reserved = 0x%x\n", hdr->reserved);
printk(KERN_INFO " .Version = 0x%x\n", hdr->version);
- /* Retreive bootloader if reqd */
+ /* Retrieve bootloader if reqd */
if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0))
/* Second bootloader in the firmware file */
filesize = hdr->reserved * 16;
diff --git a/drivers/media/video/saa7164/saa7164-types.h b/drivers/media/video/saa7164/saa7164-types.h
index df1d2997fa6c..1d2140a3eb38 100644
--- a/drivers/media/video/saa7164/saa7164-types.h
+++ b/drivers/media/video/saa7164/saa7164-types.h
@@ -412,7 +412,7 @@ struct tmComResVBIFormatDescrHeader {
u8 StartLine; /* NTSC Start = 10 */
u8 EndLine; /* NTSC = 21 */
u8 FieldRate; /* 60 for NTSC */
- u8 bNumLines; /* Unsed - scheduled for removal */
+ u8 bNumLines; /* Unused - scheduled for removal */
} __attribute__((packed));
struct tmComResProbeCommit {
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
index 9e5b01c29cf5..bc1fcedba874 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -148,7 +148,7 @@ static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)
}
}
- /* Allocate some kenrel kernel buffers for copying
+ /* Allocate some kernel buffers for copying
* to userpsace.
*/
len = params->numberoflines * params->pitch;
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 3fe54bf41142..3ae5c9c58cba 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
@@ -106,6 +107,7 @@ struct sh_mobile_ceu_dev {
struct vb2_alloc_ctx *alloc_ctx;
struct sh_mobile_ceu_info *pdata;
+ struct completion complete;
u32 cflcr;
@@ -114,6 +116,7 @@ struct sh_mobile_ceu_dev {
unsigned int image_mode:1;
unsigned int is_16bit:1;
+ unsigned int frozen:1;
};
struct sh_mobile_ceu_cam {
@@ -273,7 +276,8 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK);
status = ceu_read(pcdev, CETCR);
ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC);
- ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
+ if (!pcdev->frozen)
+ ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
@@ -287,6 +291,11 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
ret = -EIO;
}
+ if (pcdev->frozen) {
+ complete(&pcdev->complete);
+ return ret;
+ }
+
if (!pcdev->active)
return ret;
@@ -378,12 +387,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
- unsigned long flags;
dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irq(&pcdev->lock);
list_add_tail(&buf->queue, &pcdev->capture);
if (!pcdev->active) {
@@ -395,7 +403,7 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
pcdev->active = vb;
sh_mobile_ceu_capture(pcdev);
}
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ spin_unlock_irq(&pcdev->lock);
}
static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
@@ -404,9 +412,8 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- unsigned long flags;
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irq(&pcdev->lock);
if (pcdev->active == vb) {
/* disable capture (release DMA buffer), reset */
@@ -417,7 +424,7 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
/* Doesn't hurt also if the list is empty */
list_del_init(&buf->queue);
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ spin_unlock_irq(&pcdev->lock);
}
static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
@@ -427,6 +434,25 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
return 0;
}
+static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
+{
+ struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ struct list_head *buf_head, *tmp;
+
+ spin_lock_irq(&pcdev->lock);
+
+ pcdev->active = NULL;
+
+ list_for_each_safe(buf_head, tmp, &pcdev->capture)
+ list_del_init(buf_head);
+
+ spin_unlock_irq(&pcdev->lock);
+
+ return sh_mobile_ceu_soft_reset(pcdev);
+}
+
static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
.queue_setup = sh_mobile_ceu_videobuf_setup,
.buf_prepare = sh_mobile_ceu_videobuf_prepare,
@@ -435,6 +461,7 @@ static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
.buf_init = sh_mobile_ceu_videobuf_init,
.wait_prepare = soc_camera_unlock,
.wait_finish = soc_camera_lock,
+ .stop_streaming = sh_mobile_ceu_stop_streaming,
};
static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
@@ -500,7 +527,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- unsigned long flags;
BUG_ON(icd != pcdev->icd);
@@ -509,13 +535,13 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
sh_mobile_ceu_soft_reset(pcdev);
/* make sure active buffer is canceled */
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irq(&pcdev->lock);
if (pcdev->active) {
list_del_init(&to_ceu_vb(pcdev->active)->queue);
vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR);
pcdev->active = NULL;
}
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ spin_unlock_irq(&pcdev->lock);
pm_runtime_put_sync(ici->v4l2_dev.dev);
@@ -891,8 +917,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
- return -EINVAL;
+ dev_warn(dev, "unsupported format code #%u: %d\n", idx, code);
+ return 0;
}
if (!pcdev->pdata->csi2_dev) {
@@ -922,7 +948,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
/* Try 2560x1920, 1280x960, 640x480, 320x240 */
mf.width = 2560 >> shift;
mf.height = 1920 >> shift;
- ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
s_mbus_fmt, &mf);
if (ret < 0)
return ret;
@@ -1224,7 +1250,7 @@ static int client_s_fmt(struct soc_camera_device *icd,
struct v4l2_cropcap cap;
int ret;
- ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
s_mbus_fmt, mf);
if (ret < 0)
return ret;
@@ -1254,7 +1280,7 @@ static int client_s_fmt(struct soc_camera_device *icd,
tmp_h = min(2 * tmp_h, max_height);
mf->width = tmp_w;
mf->height = tmp_h;
- ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
s_mbus_fmt, mf);
dev_geo(dev, "Camera scaled to %ux%u\n",
mf->width, mf->height);
@@ -1330,7 +1356,7 @@ static int client_scale(struct soc_camera_device *icd,
/*
* CEU can scale and crop, but we don't want to waste bandwidth and kill the
* framerate by always requesting the maximum image from the client. See
- * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of
+ * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of
* scaling and cropping algorithms and for the meaning of referenced here steps.
*/
static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
@@ -1377,10 +1403,6 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
if (mf.width > 2560 || mf.height > 1920)
return -EINVAL;
- /* Cache camera output window */
- cam->width = mf.width;
- cam->height = mf.height;
-
/* 4. Calculate camera scales */
scale_cam_h = calc_generic_scale(cam_rect->width, mf.width);
scale_cam_v = calc_generic_scale(cam_rect->height, mf.height);
@@ -1389,6 +1411,39 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
interm_width = scale_down(rect->width, scale_cam_h);
interm_height = scale_down(rect->height, scale_cam_v);
+ if (interm_width < icd->user_width) {
+ u32 new_scale_h;
+
+ new_scale_h = calc_generic_scale(rect->width, icd->user_width);
+
+ mf.width = scale_down(cam_rect->width, new_scale_h);
+ }
+
+ if (interm_height < icd->user_height) {
+ u32 new_scale_v;
+
+ new_scale_v = calc_generic_scale(rect->height, icd->user_height);
+
+ mf.height = scale_down(cam_rect->height, new_scale_v);
+ }
+
+ if (interm_width < icd->user_width || interm_height < icd->user_height) {
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, (int)icd, video,
+ s_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height);
+ scale_cam_h = calc_generic_scale(cam_rect->width, mf.width);
+ scale_cam_v = calc_generic_scale(cam_rect->height, mf.height);
+ interm_width = scale_down(rect->width, scale_cam_h);
+ interm_height = scale_down(rect->height, scale_cam_v);
+ }
+
+ /* Cache camera output window */
+ cam->width = mf.width;
+ cam->height = mf.height;
+
if (pcdev->image_mode) {
out_width = min(interm_width, icd->user_width);
out_height = min(interm_height, icd->user_height);
@@ -1658,7 +1713,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
mf.code = xlate->code;
mf.colorspace = pix->colorspace;
- ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf);
if (ret < 0)
return ret;
@@ -1682,7 +1737,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
*/
mf.width = 2560;
mf.height = 1920;
- ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
try_mbus_fmt, &mf);
if (ret < 0) {
/* Shouldn't actually happen... */
@@ -1704,6 +1759,63 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
return ret;
}
+static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
+ struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ u32 out_width = icd->user_width, out_height = icd->user_height;
+ int ret;
+
+ /* Freeze queue */
+ pcdev->frozen = 1;
+ /* Wait for frame */
+ ret = wait_for_completion_interruptible(&pcdev->complete);
+ /* Stop the client */
+ ret = v4l2_subdev_call(sd, video, s_stream, 0);
+ if (ret < 0)
+ dev_warn(icd->dev.parent,
+ "Client failed to stop the stream: %d\n", ret);
+ else
+ /* Do the crop, if it fails, there's nothing more we can do */
+ sh_mobile_ceu_set_crop(icd, a);
+
+ dev_geo(icd->dev.parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
+
+ if (icd->user_width != out_width || icd->user_height != out_height) {
+ struct v4l2_format f = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .fmt.pix = {
+ .width = out_width,
+ .height = out_height,
+ .pixelformat = icd->current_fmt->host_fmt->fourcc,
+ .field = pcdev->field,
+ .colorspace = icd->colorspace,
+ },
+ };
+ ret = sh_mobile_ceu_set_fmt(icd, &f);
+ if (!ret && (out_width != f.fmt.pix.width ||
+ out_height != f.fmt.pix.height))
+ ret = -EINVAL;
+ if (!ret) {
+ icd->user_width = out_width;
+ icd->user_height = out_height;
+ ret = sh_mobile_ceu_set_bus_param(icd,
+ icd->current_fmt->host_fmt->fourcc);
+ }
+ }
+
+ /* Thaw the queue */
+ pcdev->frozen = 0;
+ spin_lock_irq(&pcdev->lock);
+ sh_mobile_ceu_capture(pcdev);
+ spin_unlock_irq(&pcdev->lock);
+ /* Start the client */
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ return ret;
+}
+
static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
{
struct soc_camera_device *icd = file->private_data;
@@ -1790,6 +1902,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.put_formats = sh_mobile_ceu_put_formats,
.get_crop = sh_mobile_ceu_get_crop,
.set_crop = sh_mobile_ceu_set_crop,
+ .set_livecrop = sh_mobile_ceu_set_livecrop,
.set_fmt = sh_mobile_ceu_set_fmt,
.try_fmt = sh_mobile_ceu_try_fmt,
.set_ctrl = sh_mobile_ceu_set_ctrl,
@@ -1856,6 +1969,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&pcdev->capture);
spin_lock_init(&pcdev->lock);
+ init_completion(&pcdev->complete);
pcdev->pdata = pdev->dev.platform_data;
if (!pcdev->pdata) {
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
index dd1b81b1442b..98b87481fa94 100644
--- a/drivers/media/video/sh_mobile_csi2.c
+++ b/drivers/media/video/sh_mobile_csi2.c
@@ -38,6 +38,8 @@ struct sh_csi2 {
void __iomem *base;
struct platform_device *pdev;
struct sh_csi2_client_config *client;
+ unsigned long (*query_bus_param)(struct soc_camera_device *);
+ int (*set_bus_param)(struct soc_camera_device *, unsigned long);
};
static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
@@ -208,6 +210,7 @@ static int sh_csi2_notify(struct notifier_block *nb,
case BUS_NOTIFY_BOUND_DRIVER:
snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
dev_name(v4l2_dev->dev), ".mipi-csi");
+ priv->subdev.grp_id = (long)icd;
ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
if (ret < 0)
@@ -215,6 +218,8 @@ static int sh_csi2_notify(struct notifier_block *nb,
priv->client = pdata->clients + i;
+ priv->set_bus_param = icd->ops->set_bus_param;
+ priv->query_bus_param = icd->ops->query_bus_param;
icd->ops->set_bus_param = sh_csi2_set_bus_param;
icd->ops->query_bus_param = sh_csi2_query_bus_param;
@@ -226,8 +231,10 @@ static int sh_csi2_notify(struct notifier_block *nb,
priv->client = NULL;
/* Driver is about to be unbound */
- icd->ops->set_bus_param = NULL;
- icd->ops->query_bus_param = NULL;
+ icd->ops->set_bus_param = priv->set_bus_param;
+ icd->ops->query_bus_param = priv->query_bus_param;
+ priv->set_bus_param = NULL;
+ priv->query_bus_param = NULL;
v4l2_device_unregister_subdev(&priv->subdev);
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index ce56a1cdbf0a..0e07c493e6f0 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -1810,7 +1810,7 @@ static int sn9c102_open(struct file *filp)
/*
We will not release the "open_mutex" lock, so that only one
process can be in the wait queue below. This way the process
- will be sleeping while holding the lock, without loosing its
+ will be sleeping while holding the lock, without losing its
priority after any wake_up().
*/
err = wait_event_interruptible_exclusive(cam->wait_open,
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 7f38549715b6..3679970dba2c 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -180,7 +180,7 @@ struct sn9c102_sensor {
It should be used to initialize the sensor only, but may also
configure part of the SN9C1XX chip if necessary. You don't need to
setup picture settings like brightness, contrast, etc.. here, if
- the corrisponding controls are implemented (see below), since
+ the corresponding controls are implemented (see below), since
they are adjusted in the core driver by calling the set_ctrl()
method after init(), where the arguments are the default values
specified in the v4l2_queryctrl list of supported controls;
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 46284489e4eb..398864370267 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -41,6 +41,11 @@
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
+#define is_streaming(ici, icd) \
+ (((ici)->ops->init_videobuf) ? \
+ (icd)->vb_vidq.streaming : \
+ vb2_is_streaming(&(icd)->vb2_vidq))
+
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
@@ -136,11 +141,50 @@ unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
}
EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
+#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
+ ((x) >> 24) & 0xff
+
+static int soc_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int ret;
+
+ dev_dbg(&icd->dev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
+ pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
+ pix->bytesperline = 0;
+ pix->sizeimage = 0;
+
+ ret = ici->ops->try_fmt(icd, f);
+ if (ret < 0)
+ return ret;
+
+ if (!pix->sizeimage) {
+ if (!pix->bytesperline) {
+ const struct soc_camera_format_xlate *xlate;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate)
+ return -EINVAL;
+
+ ret = soc_mbus_bytes_per_line(pix->width,
+ xlate->host_fmt);
+ if (ret > 0)
+ pix->bytesperline = ret;
+ }
+ if (pix->bytesperline)
+ pix->sizeimage = pix->bytesperline * pix->height;
+ }
+
+ return 0;
+}
+
static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
@@ -149,7 +193,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
/* limit format to hardware capabilities */
- return ici->ops->try_fmt(icd, f);
+ return soc_camera_try_fmt(icd, f);
}
static int soc_camera_enum_input(struct file *file, void *priv,
@@ -319,8 +363,6 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
if (!icd->user_formats)
return -ENOMEM;
- icd->num_user_formats = fmts;
-
dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
/* Second pass - actually fill data formats */
@@ -328,9 +370,10 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
for (i = 0; i < raw_fmts; i++)
if (!ici->ops->get_formats) {
v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
- icd->user_formats[i].host_fmt =
+ icd->user_formats[fmts].host_fmt =
soc_mbus_get_fmtdesc(code);
- icd->user_formats[i].code = code;
+ if (icd->user_formats[fmts].host_fmt)
+ icd->user_formats[fmts++].code = code;
} else {
ret = ici->ops->get_formats(icd, i,
&icd->user_formats[fmts]);
@@ -339,12 +382,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
fmts += ret;
}
+ icd->num_user_formats = fmts;
icd->current_fmt = &icd->user_formats[0];
return 0;
egfmt:
- icd->num_user_formats = 0;
vfree(icd->user_formats);
return ret;
}
@@ -362,9 +405,6 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
icd->user_formats = NULL;
}
-#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
- ((x) >> 24) & 0xff
-
/* Called with .vb_lock held, or from the first open(2), see comment there */
static int soc_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
@@ -377,7 +417,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
pixfmtstr(pix->pixelformat), pix->width, pix->height);
/* We always call try_fmt() before set_fmt() or set_crop() */
- ret = ici->ops->try_fmt(icd, f);
+ ret = soc_camera_try_fmt(icd, f);
if (ret < 0)
return ret;
@@ -626,7 +666,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
if (icd->streamer && icd->streamer != file)
return -EBUSY;
- if (icd->vb_vidq.bufs[0]) {
+ if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) {
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
return -EBUSY;
}
@@ -867,14 +907,17 @@ static int soc_camera_s_crop(struct file *file, void *fh,
if (ret < 0) {
dev_err(&icd->dev,
"S_CROP denied: getting current crop failed\n");
- } else if (icd->vb_vidq.bufs[0] &&
- (a->c.width != current_crop.c.width ||
- a->c.height != current_crop.c.height)) {
+ } else if ((a->c.width == current_crop.c.width &&
+ a->c.height == current_crop.c.height) ||
+ !is_streaming(ici, icd)) {
+ /* same size or not streaming - use .set_crop() */
+ ret = ici->ops->set_crop(icd, a);
+ } else if (ici->ops->set_livecrop) {
+ ret = ici->ops->set_livecrop(icd, a);
+ } else {
dev_err(&icd->dev,
"S_CROP denied: queue initialised and sizes differ\n");
ret = -EBUSY;
- } else {
- ret = ici->ops->set_crop(icd, a);
}
return ret;
@@ -996,10 +1039,11 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
{
struct i2c_client *client =
to_i2c_client(to_soc_camera_control(icd));
+ struct i2c_adapter *adap = client->adapter;
dev_set_drvdata(&icd->dev, NULL);
v4l2_device_unregister_subdev(i2c_get_clientdata(client));
i2c_unregister_device(client);
- i2c_put_adapter(client->adapter);
+ i2c_put_adapter(adap);
}
#else
#define soc_camera_init_i2c(icd, icl) (-ENODEV)
@@ -1071,6 +1115,9 @@ static int soc_camera_probe(struct device *dev)
}
}
+ sd = soc_camera_to_subdev(icd);
+ sd->grp_id = (long)icd;
+
/* At this point client .probe() should have run already */
ret = soc_camera_init_user_formats(icd);
if (ret < 0)
@@ -1092,7 +1139,6 @@ static int soc_camera_probe(struct device *dev)
goto evidstart;
/* Try to improve our guess of a reasonable window format */
- sd = soc_camera_to_subdev(icd);
if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
icd->user_width = mf.width;
icd->user_height = mf.height;
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index ed77aa055b63..bea7c9cf4f88 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -15,132 +15,329 @@
#include <media/v4l2-mediabus.h>
#include <media/soc_mediabus.h>
-#define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1)
-
-static const struct soc_mbus_pixelfmt mbus_fmt[] = {
- [MBUS_IDX(YUYV8_2X8)] = {
+static const struct soc_mbus_lookup mbus_fmt[] = {
+{
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YVYU8_2X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(UYVY8_2X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(VYUY8_2X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB555_2X8_PADHI_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555,
.name = "RGB555",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB555_2X8_PADHI_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555X,
.name = "RGB555X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB565_2X8_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB565_2X8_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565X,
.name = "RGB565X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR8_1X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.name = "Bayer 8 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_1X10)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(Y8_1X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_Y8_1X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_GREY,
.name = "Grey",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(Y10_1X10)] = {
+}, {
+ .code = V4L2_MBUS_FMT_Y10_1X10,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_Y10,
.name = "Grey 10bit",
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADLO,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADLO,
.order = SOC_MBUS_ORDER_BE,
},
+}, {
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .name = "JPEG",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_VARIABLE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .name = "RGB444",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .name = "YUYV 4:2:0",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1_5X8,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_1_5X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .name = "YVYU 4:2:0",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1_5X8,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_UYVY8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .name = "UYVY 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_VYUY8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .name = "VYUY 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YUYV8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .name = "YUYV 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .name = "YVYU 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .name = "Bayer 8 GRBG",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8,
+ .name = "Bayer 10 BGGR DPCM 8",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGBRG10_1X10,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .name = "Bayer 10 GBRG",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .name = "Bayer 10 GRBG",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SRGGB10_1X10,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .name = "Bayer 10 RGGB",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .name = "Bayer 12 BGGR",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGBRG12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .name = "Bayer 12 GBRG",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .name = "Bayer 12 GRBG",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SRGGB12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .name = "Bayer 12 RGGB",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+},
};
-int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf)
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
+ unsigned int *numerator, unsigned int *denominator)
{
switch (mf->packing) {
case SOC_MBUS_PACKING_NONE:
case SOC_MBUS_PACKING_EXTEND16:
- return 1;
+ *numerator = 1;
+ *denominator = 1;
+ return 0;
case SOC_MBUS_PACKING_2X8_PADHI:
case SOC_MBUS_PACKING_2X8_PADLO:
- return 2;
+ *numerator = 2;
+ *denominator = 1;
+ return 0;
+ case SOC_MBUS_PACKING_1_5X8:
+ *numerator = 3;
+ *denominator = 2;
+ return 0;
+ case SOC_MBUS_PACKING_VARIABLE:
+ *numerator = 0;
+ *denominator = 1;
+ return 0;
}
return -EINVAL;
}
@@ -155,18 +352,34 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
case SOC_MBUS_PACKING_2X8_PADLO:
case SOC_MBUS_PACKING_EXTEND16:
return width * 2;
+ case SOC_MBUS_PACKING_1_5X8:
+ return width * 3 / 2;
+ case SOC_MBUS_PACKING_VARIABLE:
+ return 0;
}
return -EINVAL;
}
EXPORT_SYMBOL(soc_mbus_bytes_per_line);
+const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
+ enum v4l2_mbus_pixelcode code,
+ const struct soc_mbus_lookup *lookup,
+ int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ if (lookup[i].code == code)
+ return &lookup[i].fmt;
+
+ return NULL;
+}
+EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
+
const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
enum v4l2_mbus_pixelcode code)
{
- if (code - V4L2_MBUS_FMT_FIXED > ARRAY_SIZE(mbus_fmt) ||
- code <= V4L2_MBUS_FMT_FIXED)
- return NULL;
- return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1;
+ return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
}
EXPORT_SYMBOL(soc_mbus_get_fmtdesc);
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index 54681a535822..b6ee1bd342dc 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -493,7 +493,7 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s,
int val, r;
struct vcontrol *lvc;
- /* exposure time is special, spread accross 2 registers */
+ /* exposure time is special, spread across 2 registers */
if (vc->id == V4L2_CID_EXPOSURE) {
int val_lower, val_upper;
@@ -538,7 +538,7 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s,
struct vcontrol *lvc;
int val = vc->value;
- /* exposure time is special, spread accross 2 registers */
+ /* exposure time is special, spread across 2 registers */
if (vc->id == V4L2_CID_EXPOSURE) {
int val_lower, val_upper;
val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 5d4cf3b3d435..22fa8202d5ca 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -171,7 +171,7 @@ static int tda9840_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index 19621ed523ec..827425c5b866 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -152,7 +152,7 @@ static int tea6415c_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 5ea840401f21..f350b6c24500 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -125,7 +125,7 @@ static int tea6420_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index a25e2b5e1944..c46a3bb95852 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -1058,11 +1058,11 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
#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_ACS 0x1f /* Auxiliary channel select (FM) 0b0000000*/
+#define TDA9875_AVL 0x20 /* Auxiliary volume gauche */
+#define TDA9875_AVR 0x21 /* Auxiliary volume droite */
+#define TDA9875_ABA 0x22 /* Auxiliary Basse */
+#define TDA9875_ATR 0x23 /* Auxiliary treble */
#define TDA9875_MSR 0x02 /* Monitor select register */
#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 07fabdd9b465..6103d1b1081e 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -267,21 +267,27 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Xceive XC4000"},
{ TUNER_ABSENT, "Dibcom 7070"},
{ TUNER_PHILIPS_TDA8290, "NXP 18271C2"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "Siano SMS1010"},
+ { TUNER_ABSENT, "Siano SMS1150"},
+ { TUNER_ABSENT, "MaxLinear 5007"},
+ { TUNER_ABSENT, "TCL M09WPP_2P_E"},
/* 160-169 */
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "Siano SMS1180"},
+ { TUNER_ABSENT, "Maxim_MAX2165"},
+ { TUNER_ABSENT, "Siano SMS1140"},
+ { TUNER_ABSENT, "Siano SMS1150 B1"},
+ { TUNER_ABSENT, "MaxLinear 111"},
+ { TUNER_ABSENT, "Dibcom 7770"},
+ { TUNER_ABSENT, "Siano SMS1180VNS"},
+ { TUNER_ABSENT, "Siano SMS1184"},
{ TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"},
- { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "TCL_M11WPP_2PN_E"},
+ /* 170-179 */
+ { TUNER_ABSENT, "MaxLinear 301"},
+ { TUNER_ABSENT, "Mirics MSi001"},
+ { TUNER_ABSENT, "MaxLinear MxL241SF"},
+ { TUNER_ABSENT, "Xceive XC5000C"},
+ { TUNER_ABSENT, "Montage M68TS2020"},
};
/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index f8138c75be8b..1aab96a88203 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -230,7 +230,7 @@ static int upd64031a_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index 28e0e6b6ca84..9bbe61700fd5 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -202,7 +202,7 @@ static int upd64083_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 68b998bd203f..8f5266157f15 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -1025,6 +1025,34 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.y_offset = -1,
.model_string = "Hauppauge WinTv-USB",
},
+ [MICROCAM_NTSC] = {
+ .interface = -1,
+ .codec = CODEC_WEBCAM,
+ .video_channels = 1,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 0,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 71,
+ .y_offset = 15,
+ .model_string = "Nogatech USB MicroCam NTSC (NV3000N)",
+ },
+ [MICROCAM_PAL] = {
+ .interface = -1,
+ .codec = CODEC_WEBCAM,
+ .video_channels = 1,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 0,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 71,
+ .y_offset = 18,
+ .model_string = "Nogatech USB MicroCam PAL (NV3001P)",
+ },
};
const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data);
@@ -1042,6 +1070,8 @@ struct usb_device_id usbvision_table[] = {
{ USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG },
{ USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN },
{ USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH },
+ { USB_DEVICE(0x0573, 0x3000), .driver_info = MICROCAM_NTSC },
+ { USB_DEVICE(0x0573, 0x3001), .driver_info = MICROCAM_PAL },
{ USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM },
{ USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
{ USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
@@ -1088,8 +1118,7 @@ struct usb_device_id usbvision_table[] = {
{ USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
{ USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
{ USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
- { USB_DEVICE(0x2304, 0x0113),
- .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
+ { USB_DEVICE(0x2304, 0x0113), .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
{ USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 },
{ USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 },
{ USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h
index 9c6ad22960d8..a51cc1185cce 100644
--- a/drivers/media/video/usbvision/usbvision-cards.h
+++ b/drivers/media/video/usbvision/usbvision-cards.h
@@ -63,5 +63,7 @@
#define PINNA_PCTV_BUNGEE_PAL_FM 62
#define HPG_WINTV 63
#define PINNA_PCTV_USB_NTSC_FM_V3 64
+#define MICROCAM_NTSC 65
+#define MICROCAM_PAL 66
extern const int usbvision_device_data_size;
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index c8feb0d6fccf..f344411a4578 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -49,10 +49,6 @@ static unsigned int core_debug;
module_param(core_debug, int, 0644);
MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
-static unsigned int force_testpattern;
-module_param(force_testpattern, int, 0644);
-MODULE_PARM_DESC(force_testpattern, "enable test pattern display [core]");
-
static int adjust_compression = 1; /* Set the compression to be adaptive */
module_param(adjust_compression, int, 0444);
MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device. Default: 1 (On)");
@@ -388,90 +384,6 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision)
}
/*
- * usbvision_testpattern()
- *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe: if TRUE then entire frame is filled, otherwise the procedure
- * continues from the current scanline.
- * pmode 0: fill the frame with solid blue color (like on VCR or TV)
- * 1: Draw a colored grid
- *
- */
-static void usbvision_testpattern(struct usb_usbvision *usbvision,
- int fullframe, int pmode)
-{
- static const char proc[] = "usbvision_testpattern";
- struct usbvision_frame *frame;
- unsigned char *f;
- int num_cell = 0;
- int scan_length = 0;
- static int num_pass;
-
- if (usbvision == NULL) {
- printk(KERN_ERR "%s: usbvision == NULL\n", proc);
- return;
- }
- if (usbvision->cur_frame == NULL) {
- printk(KERN_ERR "%s: usbvision->cur_frame is NULL.\n", proc);
- return;
- }
-
- /* Grab the current frame */
- frame = usbvision->cur_frame;
-
- /* Optionally start at the beginning */
- if (fullframe) {
- frame->curline = 0;
- frame->scanlength = 0;
- }
-
- /* Form every scan line */
- for (; frame->curline < frame->frmheight; frame->curline++) {
- int i;
-
- f = frame->data + (usbvision->curwidth * 3 * frame->curline);
- for (i = 0; i < usbvision->curwidth; i++) {
- unsigned char cb = 0x80;
- unsigned char cg = 0;
- unsigned char cr = 0;
-
- if (pmode == 1) {
- if (frame->curline % 32 == 0)
- cb = 0, cg = cr = 0xFF;
- else if (i % 32 == 0) {
- if (frame->curline % 32 == 1)
- num_cell++;
- cb = 0, cg = cr = 0xFF;
- } else {
- cb =
- ((num_cell * 7) +
- num_pass) & 0xFF;
- cg =
- ((num_cell * 5) +
- num_pass * 2) & 0xFF;
- cr =
- ((num_cell * 3) +
- num_pass * 3) & 0xFF;
- }
- } else {
- /* Just the blue screen */
- }
-
- *f++ = cb;
- *f++ = cg;
- *f++ = cr;
- scan_length += 3;
- }
- }
-
- frame->grabstate = frame_state_done;
- frame->scanlength += scan_length;
- ++num_pass;
-}
-
-/*
* usbvision_decompress_alloc()
*
* allocates intermediate buffer for decompression
@@ -571,10 +483,6 @@ static enum parse_state usbvision_find_header(struct usb_usbvision *usbvision)
frame->scanstate = scan_state_lines;
frame->curline = 0;
- if (force_testpattern) {
- usbvision_testpattern(usbvision, 1, 1);
- return parse_state_next_frame;
- }
return parse_state_continue;
}
@@ -1679,6 +1587,55 @@ int usbvision_power_off(struct usb_usbvision *usbvision)
return err_code;
}
+/* configure webcam image sensor using the serial port */
+static int usbvision_init_webcam(struct usb_usbvision *usbvision)
+{
+ int rc;
+ int i;
+ static char init_values[38][3] = {
+ { 0x04, 0x12, 0x08 }, { 0x05, 0xff, 0xc8 }, { 0x06, 0x18, 0x07 }, { 0x07, 0x90, 0x00 },
+ { 0x09, 0x00, 0x00 }, { 0x0a, 0x00, 0x00 }, { 0x0b, 0x08, 0x00 }, { 0x0d, 0xcc, 0xcc },
+ { 0x0e, 0x13, 0x14 }, { 0x10, 0x9b, 0x83 }, { 0x11, 0x5a, 0x3f }, { 0x12, 0xe4, 0x73 },
+ { 0x13, 0x88, 0x84 }, { 0x14, 0x89, 0x80 }, { 0x15, 0x00, 0x20 }, { 0x16, 0x00, 0x00 },
+ { 0x17, 0xff, 0xa0 }, { 0x18, 0x6b, 0x20 }, { 0x19, 0x22, 0x40 }, { 0x1a, 0x10, 0x07 },
+ { 0x1b, 0x00, 0x47 }, { 0x1c, 0x03, 0xe0 }, { 0x1d, 0x00, 0x00 }, { 0x1e, 0x00, 0x00 },
+ { 0x1f, 0x00, 0x00 }, { 0x20, 0x00, 0x00 }, { 0x21, 0x00, 0x00 }, { 0x22, 0x00, 0x00 },
+ { 0x23, 0x00, 0x00 }, { 0x24, 0x00, 0x00 }, { 0x25, 0x00, 0x00 }, { 0x26, 0x00, 0x00 },
+ { 0x27, 0x00, 0x00 }, { 0x28, 0x00, 0x00 }, { 0x29, 0x00, 0x00 }, { 0x08, 0x80, 0x60 },
+ { 0x0f, 0x2d, 0x24 }, { 0x0c, 0x80, 0x80 }
+ };
+ char value[3];
+
+ /* the only difference between PAL and NTSC init_values */
+ if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_NTSC)
+ init_values[4][1] = 0x34;
+
+ for (i = 0; i < sizeof(init_values) / 3; i++) {
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
+ memcpy(value, init_values[i], 3);
+ rc = usb_control_msg(usbvision->dev,
+ usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_SER_DAT1, value,
+ 3, HZ);
+ if (rc < 0)
+ return rc;
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SIO);
+ /* write 3 bytes to the serial port using SIO mode */
+ usbvision_write_reg(usbvision, USBVISION_SER_CONT, 3 | 0x10);
+ usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, 0);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
+ usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_IO_2);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_DAT_IO);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT | USBVISION_DAT_IO);
+ }
+
+ return 0;
+}
+
/*
* usbvision_set_video_format()
*
@@ -1797,6 +1754,13 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+ if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_PAL)
+ frame_drop = 25;
+ else
+ frame_drop = 30;
+ }
+
/* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
=> frame_skip = 4;
=> frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
@@ -2046,6 +2010,12 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */
}
+ /* webcam is only 480 pixels wide, both PAL and NTSC version */
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+ value[0] = 0xe0;
+ value[1] = 0x01; /* 0x01E0 -> 480 Input video line length */
+ }
+
if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) {
value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
@@ -2148,7 +2118,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
(__u16) USBVISION_DRM_PRM1, value, 8, HZ);
if (rc < 0) {
- dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc);
+ dev_err(&usbvision->dev->dev, "%s: ERROR=%d\n", __func__, rc);
return rc;
}
@@ -2180,8 +2150,15 @@ int usbvision_power_on(struct usb_usbvision *usbvision)
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_RES2);
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+ usbvision_write_reg(usbvision, USBVISION_VIN_REG1,
+ USBVISION_16_422_SYNC | USBVISION_HVALID_PO);
+ usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+ USBVISION_NOHVALID | USBVISION_KEEP_BLANK);
+ }
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_PWR_VID);
+ mdelay(10);
err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
if (err_code == 1)
@@ -2310,6 +2287,8 @@ int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel)
int usbvision_setup(struct usb_usbvision *usbvision, int format)
{
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM)
+ usbvision_init_webcam(usbvision);
usbvision_set_video_format(usbvision, format);
usbvision_set_dram_settings(usbvision);
usbvision_set_compress_params(usbvision);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 05b1344181cd..d7f97513b289 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -222,7 +222,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
- printk(KERN_ERR "usbvision_register: can't write reg\n");
+ printk(KERN_ERR "usbvision_i2c_register: can't write reg\n");
return -EBUSY;
}
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 6083137f0bf8..ea8ea8a48dfe 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -70,8 +70,9 @@
#include "usbvision.h"
#include "usbvision-cards.h"
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, \
-Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR \
+ "Joerg Heckenbach <joerg@heckenbach-aw.de>, " \
+ "Dwaine Garden <DwaineGarden@rogers.com>"
#define DRIVER_NAME "usbvision"
#define DRIVER_ALIAS "USBVision"
#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
@@ -1470,7 +1471,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
/* This should be here to make i2c clients to be able to register */
/* first switch off audio */
- usbvision_audio_off(usbvision);
+ if (usbvision_device_data[model].audio_channels > 0)
+ usbvision_audio_off(usbvision);
if (!power_on_at_open) {
/* and then power up the noisy tuner */
usbvision_power_on(usbvision);
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index 8074787fd1ac..43cf61fe4943 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -59,6 +59,11 @@
#define USBVISION_AUDIO_RADIO 2
#define USBVISION_AUDIO_MUTE 3
#define USBVISION_SER_MODE 0x07
+ #define USBVISION_CLK_OUT (1 << 0)
+ #define USBVISION_DAT_IO (1 << 1)
+ #define USBVISION_SENS_OUT (1 << 2)
+ #define USBVISION_SER_MODE_SOFT (0 << 4)
+ #define USBVISION_SER_MODE_SIO (1 << 4)
#define USBVISION_SER_ADRS 0x08
#define USBVISION_SER_CONT 0x09
#define USBVISION_SER_DAT1 0x0A
@@ -328,6 +333,7 @@ struct usbvision_frame {
#define CODEC_SAA7113 7113
#define CODEC_SAA7111 7111
+#define CODEC_WEBCAM 3000
#define BRIDGE_NT1003 1003
#define BRIDGE_NT1004 1004
#define BRIDGE_NT1005 1005
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 59f8a9ad3796..a4db26fa2f53 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -42,281 +42,313 @@ static struct uvc_control_info uvc_ctrls[] = {
.selector = UVC_PU_BRIGHTNESS_CONTROL,
.index = 0,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_CONTRAST_CONTROL,
.index = 1,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_HUE_CONTROL,
.index = 2,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_SATURATION_CONTROL,
.index = 3,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_SHARPNESS_CONTROL,
.index = 4,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_GAMMA_CONTROL,
.index = 5,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
.index = 6,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.index = 7,
.size = 4,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
.index = 8,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_GAIN_CONTROL,
.index = 9,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.index = 10,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_HUE_AUTO_CONTROL,
.index = 11,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
.index = 12,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
.index = 13,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL,
.index = 14,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
.index = 15,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL,
.index = 16,
.size = 1,
- .flags = UVC_CONTROL_GET_CUR,
+ .flags = UVC_CTRL_FLAG_GET_CUR,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL,
.index = 17,
.size = 1,
- .flags = UVC_CONTROL_GET_CUR,
+ .flags = UVC_CTRL_FLAG_GET_CUR,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_SCANNING_MODE_CONTROL,
.index = 0,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_AE_MODE_CONTROL,
.index = 1,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_AE_PRIORITY_CONTROL,
.index = 2,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
.index = 3,
.size = 4,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
.index = 4,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
.index = 5,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_FOCUS_RELATIVE_CONTROL,
.index = 6,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_IRIS_ABSOLUTE_CONTROL,
.index = 7,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_IRIS_RELATIVE_CONTROL,
.index = 8,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
.index = 9,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
.index = 10,
.size = 3,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
.index = 11,
.size = 8,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_PANTILT_RELATIVE_CONTROL,
.index = 12,
.size = 4,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ROLL_ABSOLUTE_CONTROL,
.index = 13,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ROLL_RELATIVE_CONTROL,
.index = 14,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_FOCUS_AUTO_CONTROL,
.index = 17,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_PRIVACY_CONTROL,
.index = 18,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
};
@@ -816,7 +848,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
{
int ret;
- if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
@@ -825,7 +857,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
return ret;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_MIN) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
@@ -833,7 +865,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
if (ret < 0)
return ret;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_MAX) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
@@ -841,7 +873,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
if (ret < 0)
return ret;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_RES) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
@@ -879,9 +911,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
v4l2_ctrl->flags = 0;
- if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR))
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR))
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (!ctrl->cached) {
@@ -890,7 +922,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
goto done;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
}
@@ -927,15 +959,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
break;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_MIN)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- if (ctrl->info.flags & UVC_CONTROL_GET_MAX)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
- if (ctrl->info.flags & UVC_CONTROL_GET_RES)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
@@ -983,6 +1015,24 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
}
menu_info = &mapping->menu_info[query_menu->index];
+
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+ s32 bitmap;
+
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ goto done;
+ }
+
+ bitmap = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ if (!(bitmap & menu_info->value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
done:
@@ -1039,7 +1089,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
* marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
* uvc_ctrl_get from using the cached value.
*/
- if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE)
ctrl->loaded = 0;
if (!ctrl->dirty)
@@ -1094,7 +1144,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0)
+ if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
return -EINVAL;
if (!ctrl->loaded) {
@@ -1136,7 +1186,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0)
+ if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) == 0)
return -EINVAL;
/* Clamp out of range values. */
@@ -1171,6 +1221,23 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
return -ERANGE;
value = mapping->menu_info[xctrl->value].value;
+
+ /* Valid menu indices are reported by the GET_RES request for
+ * UVC controls that support it.
+ */
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ }
+
+ step = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ if (!(step & value))
+ return -ERANGE;
+ }
+
break;
default:
@@ -1183,7 +1250,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
* operation.
*/
if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) {
- if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) {
+ if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) {
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
0, ctrl->info.size);
} else {
@@ -1230,17 +1297,17 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
static const struct uvc_ctrl_fixup fixups[] = {
{ { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
- UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
- UVC_CONTROL_AUTO_UPDATE },
+ UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+ UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE },
{ { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
- UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
- UVC_CONTROL_AUTO_UPDATE },
+ UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+ UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE },
{ { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
- UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
- UVC_CONTROL_AUTO_UPDATE },
+ UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+ UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE },
};
unsigned int i;
@@ -1297,21 +1364,23 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
goto done;
}
- info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX
- | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF
- | (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0)
- | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0)
+ info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
+ | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
+ | (data[0] & UVC_CONTROL_CAP_GET ?
+ UVC_CTRL_FLAG_GET_CUR : 0)
+ | (data[0] & UVC_CONTROL_CAP_SET ?
+ UVC_CTRL_FLAG_SET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
- UVC_CONTROL_AUTO_UPDATE : 0);
+ UVC_CTRL_FLAG_AUTO_UPDATE : 0);
uvc_ctrl_fixup_xu_info(dev, ctrl, info);
uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
"flags { get %u set %u auto %u }.\n",
info->entity, info->selector, info->size,
- (info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0,
- (info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0,
- (info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0);
+ (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0,
+ (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0,
+ (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0);
done:
kfree(data);
@@ -1344,32 +1413,33 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
}
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control *xctrl, int set)
+ struct uvc_xu_control_query *xqry)
{
struct uvc_entity *entity;
- struct uvc_control *ctrl = NULL;
+ struct uvc_control *ctrl;
unsigned int i, found = 0;
- int restore = 0;
- __u8 *data;
+ __u32 reqflags;
+ __u16 size;
+ __u8 *data = NULL;
int ret;
/* Find the extension unit. */
list_for_each_entry(entity, &chain->entities, chain) {
if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
- entity->id == xctrl->unit)
+ entity->id == xqry->unit)
break;
}
- if (entity->id != xctrl->unit) {
+ if (entity->id != xqry->unit) {
uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
- xctrl->unit);
- return -EINVAL;
+ xqry->unit);
+ return -ENOENT;
}
/* Find the control and perform delayed initialization if needed. */
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
- if (ctrl->index == xctrl->selector - 1) {
+ if (ctrl->index == xqry->selector - 1) {
found = 1;
break;
}
@@ -1377,8 +1447,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
if (!found) {
uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
- entity->extension.guidExtensionCode, xctrl->selector);
- return -EINVAL;
+ entity->extension.guidExtensionCode, xqry->selector);
+ return -ENOENT;
}
if (mutex_lock_interruptible(&chain->ctrl_mutex))
@@ -1390,43 +1460,72 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
goto done;
}
- /* Validate control data size. */
- if (ctrl->info.size != xctrl->size) {
+ /* Validate the required buffer size and flags for the request */
+ reqflags = 0;
+ size = ctrl->info.size;
+
+ switch (xqry->query) {
+ case UVC_GET_CUR:
+ reqflags = UVC_CTRL_FLAG_GET_CUR;
+ break;
+ case UVC_GET_MIN:
+ reqflags = UVC_CTRL_FLAG_GET_MIN;
+ break;
+ case UVC_GET_MAX:
+ reqflags = UVC_CTRL_FLAG_GET_MAX;
+ break;
+ case UVC_GET_DEF:
+ reqflags = UVC_CTRL_FLAG_GET_DEF;
+ break;
+ case UVC_GET_RES:
+ reqflags = UVC_CTRL_FLAG_GET_RES;
+ break;
+ case UVC_SET_CUR:
+ reqflags = UVC_CTRL_FLAG_SET_CUR;
+ break;
+ case UVC_GET_LEN:
+ size = 2;
+ break;
+ case UVC_GET_INFO:
+ size = 1;
+ break;
+ default:
ret = -EINVAL;
goto done;
}
- if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) ||
- (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) {
- ret = -EINVAL;
+ if (size != xqry->size) {
+ ret = -ENOBUFS;
goto done;
}
- memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
- data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
- restore = set;
+ if (reqflags && !(ctrl->info.flags & reqflags)) {
+ ret = -EBADRQC;
+ goto done;
+ }
- if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
+ data = kmalloc(size, GFP_KERNEL);
+ if (data == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (xqry->query == UVC_SET_CUR &&
+ copy_from_user(data, xqry->data, size)) {
ret = -EFAULT;
goto done;
}
- ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
- xctrl->unit, chain->dev->intfnum, xctrl->selector,
- data, xctrl->size);
+ ret = uvc_query_ctrl(chain->dev, xqry->query, xqry->unit,
+ chain->dev->intfnum, xqry->selector, data, size);
if (ret < 0)
goto done;
- if (!set && copy_to_user(xctrl->data, data, xctrl->size))
+ if (xqry->query != UVC_SET_CUR &&
+ copy_to_user(xqry->data, data, size))
ret = -EFAULT;
done:
- if (ret && restore)
- memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
- xctrl->size);
-
+ kfree(data);
mutex_unlock(&chain->ctrl_mutex);
return ret;
}
@@ -1458,7 +1557,7 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
ctrl = &entity->controls[i];
if (!ctrl->initialized || !ctrl->modified ||
- (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0)
+ (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
continue;
printk(KERN_INFO "restoring control %pUl/%u/%u\n",
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 6459b8cba223..823f4b389745 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -84,6 +84,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_YUV420,
},
{
+ .name = "YUV 4:2:0 (M420)",
+ .guid = UVC_GUID_FORMAT_M420,
+ .fcc = V4L2_PIX_FMT_M420,
+ },
+ {
.name = "YUV 4:2:2 (UYVY)",
.guid = UVC_GUID_FORMAT_UYVY,
.fcc = V4L2_PIX_FMT_UYVY,
@@ -103,6 +108,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.guid = UVC_GUID_FORMAT_BY8,
.fcc = V4L2_PIX_FMT_SBGGR8,
},
+ {
+ .name = "RGB565",
+ .guid = UVC_GUID_FORMAT_RGBP,
+ .fcc = V4L2_PIX_FMT_RGB565,
+ },
};
/* ------------------------------------------------------------------------
@@ -2077,6 +2087,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Hercules Classic Silver */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x06f8,
+ .idProduct = 0x300c,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
/* ViMicro Vega */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2123,6 +2142,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* JMicron USB2.0 XGA WebCam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x152d,
+ .idProduct = 0x0310,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* Syntek (HP Spartan) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index f14581bd707f..109a06384a8f 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -424,7 +424,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
break;
}
- if (i == queue->count || size != queue->buf_size) {
+ if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
ret = -EINVAL;
goto done;
}
@@ -436,6 +436,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO;
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+#ifdef CONFIG_MMU
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -445,6 +446,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
+#endif
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
@@ -488,6 +490,36 @@ done:
return mask;
}
+#ifndef CONFIG_MMU
+/*
+ * Get unmapped area.
+ *
+ * NO-MMU arch need this function to make mmap() work correctly.
+ */
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff)
+{
+ struct uvc_buffer *buffer;
+ unsigned int i;
+ unsigned long ret;
+
+ mutex_lock(&queue->mutex);
+ for (i = 0; i < queue->count; ++i) {
+ buffer = &queue->buffer[i];
+ if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
+ break;
+ }
+ if (i == queue->count) {
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = (unsigned long)queue->mem + buffer->buf.m.offset;
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+#endif
+
/*
* Enable or disable the video buffers queue.
*
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 9005a8d9d5f8..543a80395b7f 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -538,6 +538,20 @@ static int uvc_v4l2_release(struct file *file)
return 0;
}
+static void uvc_v4l2_ioctl_warn(void)
+{
+ static int warned;
+
+ if (warned)
+ return;
+
+ uvc_printk(KERN_INFO, "Deprecated UVCIOC_CTRL_{ADD,MAP_OLD,GET,SET} "
+ "ioctls will be removed in 2.6.42.\n");
+ uvc_printk(KERN_INFO, "See http://www.ideasonboard.org/uvc/upgrade/ "
+ "for upgrade instructions.\n");
+ warned = 1;
+}
+
static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
@@ -1018,21 +1032,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
return -EINVAL;
- /* Dynamic controls. */
- case UVCIOC_CTRL_ADD:
- /* Legacy ioctl, kept for API compatibility reasons */
+ /* Dynamic controls. UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD,
+ * UVCIOC_CTRL_GET and UVCIOC_CTRL_SET are deprecated and scheduled for
+ * removal in 2.6.42.
+ */
+ case __UVCIOC_CTRL_ADD:
+ uvc_v4l2_ioctl_warn();
return -EEXIST;
- case UVCIOC_CTRL_MAP_OLD:
+ case __UVCIOC_CTRL_MAP_OLD:
+ uvc_v4l2_ioctl_warn();
+ case __UVCIOC_CTRL_MAP:
case UVCIOC_CTRL_MAP:
return uvc_ioctl_ctrl_map(chain, arg,
- cmd == UVCIOC_CTRL_MAP_OLD);
+ cmd == __UVCIOC_CTRL_MAP_OLD);
- case UVCIOC_CTRL_GET:
- return uvc_xu_ctrl_query(chain, arg, 0);
+ case __UVCIOC_CTRL_GET:
+ case __UVCIOC_CTRL_SET:
+ {
+ struct uvc_xu_control *xctrl = arg;
+ struct uvc_xu_control_query xqry = {
+ .unit = xctrl->unit,
+ .selector = xctrl->selector,
+ .query = cmd == __UVCIOC_CTRL_GET
+ ? UVC_GET_CUR : UVC_SET_CUR,
+ .size = xctrl->size,
+ .data = xctrl->data,
+ };
+
+ uvc_v4l2_ioctl_warn();
+ return uvc_xu_ctrl_query(chain, &xqry);
+ }
- case UVCIOC_CTRL_SET:
- return uvc_xu_ctrl_query(chain, arg, 1);
+ case UVCIOC_CTRL_QUERY:
+ return uvc_xu_ctrl_query(chain, arg);
default:
uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
@@ -1081,6 +1114,20 @@ static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
return uvc_queue_poll(&stream->queue, file, wait);
}
+#ifndef CONFIG_MMU
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct uvc_fh *handle = file->private_data;
+ struct uvc_streaming *stream = handle->stream;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
+
+ return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
+}
+#endif
+
const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
@@ -1089,5 +1136,8 @@ const struct v4l2_file_operations uvc_fops = {
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
+#ifndef CONFIG_MMU
+ .get_unmapped_area = uvc_v4l2_get_unmapped_area,
+#endif
};
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 545c0294813d..fc766b9f24c5 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -394,11 +394,11 @@ int uvc_commit_video(struct uvc_streaming *stream,
*
* uvc_video_decode_end is called with header data at the end of a bulk or
* isochronous payload. It performs any additional header data processing and
- * returns 0 or a negative error code if an error occured. As header data have
+ * returns 0 or a negative error code if an error occurred. As header data have
* already been processed by uvc_video_decode_start, this functions isn't
* required to perform sanity checks a second time.
*
- * For isochronous transfers where a payload is always transfered in a single
+ * For isochronous transfers where a payload is always transferred in a single
* URB, the three functions will be called in a row.
*
* To let the decoder process header data and update its internal state even
@@ -658,7 +658,7 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
buf);
} while (ret == -EAGAIN);
- /* If an error occured skip the rest of the payload. */
+ /* If an error occurred skip the rest of the payload. */
if (ret < 0 || buf == NULL) {
stream->bulk.skip_payload = 1;
} else {
@@ -821,7 +821,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
return stream->urb_size / psize;
/* Compute the number of packets. Bulk endpoints might transfer UVC
- * payloads accross multiple URBs.
+ * payloads across multiple URBs.
*/
npackets = DIV_ROUND_UP(size, psize);
if (npackets > UVC_MAX_PACKETS)
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 45f01e7e13d2..7cf224bae2e5 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -4,6 +4,14 @@
#include <linux/kernel.h>
#include <linux/videodev2.h>
+#ifndef __KERNEL__
+/*
+ * This header provides binary compatibility with applications using the private
+ * uvcvideo API. This API is deprecated and will be removed in 2.6.42.
+ * Applications should be recompiled against the public linux/uvcvideo.h header.
+ */
+#warn "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
+
/*
* Dynamic controls
*/
@@ -23,32 +31,18 @@
#define UVC_CONTROL_GET_MAX (1 << 3)
#define UVC_CONTROL_GET_RES (1 << 4)
#define UVC_CONTROL_GET_DEF (1 << 5)
-/* Control should be saved at suspend and restored at resume. */
#define UVC_CONTROL_RESTORE (1 << 6)
-/* Control can be updated by the camera. */
#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
UVC_CONTROL_GET_DEF)
-struct uvc_xu_control_info {
- __u8 entity[16];
- __u8 index;
- __u8 selector;
- __u16 size;
- __u32 flags;
-};
-
struct uvc_menu_info {
__u32 value;
__u8 name[32];
};
-struct uvc_xu_control_mapping_old {
- __u8 reserved[64];
-};
-
struct uvc_xu_control_mapping {
__u32 id;
__u8 name[32];
@@ -57,7 +51,7 @@ struct uvc_xu_control_mapping {
__u8 size;
__u8 offset;
- enum v4l2_ctrl_type v4l2_type;
+ __u32 v4l2_type;
__u32 data_type;
struct uvc_menu_info __user *menu_info;
@@ -66,6 +60,20 @@ struct uvc_xu_control_mapping {
__u32 reserved[4];
};
+#endif
+
+struct uvc_xu_control_info {
+ __u8 entity[16];
+ __u8 index;
+ __u8 selector;
+ __u16 size;
+ __u32 flags;
+};
+
+struct uvc_xu_control_mapping_old {
+ __u8 reserved[64];
+};
+
struct uvc_xu_control {
__u8 unit;
__u8 selector;
@@ -73,16 +81,25 @@ struct uvc_xu_control {
__u8 __user *data;
};
+#ifndef __KERNEL__
#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old)
#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
+#else
+#define __UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
+#define __UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old)
+#define __UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
+#define __UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
+#define __UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
+#endif
#ifdef __KERNEL__
#include <linux/poll.h>
#include <linux/usb/video.h>
+#include <linux/uvcvideo.h>
/* --------------------------------------------------------------------------
* UVC constants
@@ -152,13 +169,19 @@ struct uvc_xu_control {
#define UVC_GUID_FORMAT_BY8 \
{ 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGBP \
+ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_M420 \
+ { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
/* ------------------------------------------------------------------------
* Driver specific constants.
*/
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 0, 0)
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 1, 0)
+#define DRIVER_VERSION "v1.1.0"
/* Number of isochronous URBs. */
#define UVC_URBS 5
@@ -580,6 +603,10 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma);
extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
+#ifndef CONFIG_MMU
+extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff);
+#endif
extern int uvc_queue_allocated(struct uvc_video_queue *queue);
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
@@ -638,7 +665,7 @@ extern int uvc_ctrl_set(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl);
extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control *ctrl, int set);
+ struct uvc_xu_control_query *xqry);
/* Utility functions */
extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
@@ -655,4 +682,3 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
#endif /* __KERNEL__ */
#endif
-
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 498e6742579e..19d5ae293780 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -352,6 +352,23 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return ret;
}
+#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_registered(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);
@@ -389,7 +406,8 @@ static int v4l2_open(struct inode *inode, struct file *filp)
video_get(vdev);
mutex_unlock(&videodev_lock);
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV) {
entity = media_entity_get(&vdev->entity);
if (!entity) {
ret = -EBUSY;
@@ -415,7 +433,8 @@ err:
/* decrease the refcount in case of an error */
if (ret) {
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV)
media_entity_put(entity);
#endif
video_put(vdev);
@@ -437,7 +456,8 @@ static int v4l2_release(struct inode *inode, struct file *filp)
mutex_unlock(vdev->lock);
}
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV)
media_entity_put(&vdev->entity);
#endif
/* decrease the refcount unconditionally since the release()
@@ -451,6 +471,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,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
@@ -686,7 +707,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
#if defined(CONFIG_MEDIA_CONTROLLER)
/* Part 5: Register the entity. */
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV) {
vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
vdev->entity.name = vdev->name;
vdev->entity.v4l.major = VIDEO_MAJOR;
@@ -733,7 +755,8 @@ void video_unregister_device(struct video_device *vdev)
return;
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV)
media_device_unregister_entity(&vdev->entity);
#endif
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 5aeaf876ba9b..4aae501f02d0 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -155,8 +155,10 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
sd->v4l2_dev = v4l2_dev;
if (sd->internal_ops && sd->internal_ops->registered) {
err = sd->internal_ops->registered(sd);
- if (err)
+ if (err) {
+ module_put(sd->owner);
return err;
+ }
}
/* This just returns 0 if either of the two args is NULL */
@@ -164,6 +166,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
if (err) {
if (sd->internal_ops && sd->internal_ops->unregistered)
sd->internal_ops->unregistered(sd);
+ module_put(sd->owner);
return err;
}
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index a01ed39e6c16..506edcc2ddeb 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -48,7 +48,7 @@
printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\
} while (0)
-/* Zero out the end of the struct pointed to by p. Everthing after, but
+/* Zero out the end of the struct pointed to by p. Everything after, but
* not including, the specified field is cleared. */
#define CLEAR_AFTER_FIELD(p, field) \
memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 0b8064490676..812729ebf09e 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -155,25 +155,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
switch (cmd) {
case VIDIOC_QUERYCTRL:
- return v4l2_subdev_queryctrl(sd, arg);
+ return v4l2_queryctrl(sd->ctrl_handler, arg);
case VIDIOC_QUERYMENU:
- return v4l2_subdev_querymenu(sd, arg);
+ return v4l2_querymenu(sd->ctrl_handler, arg);
case VIDIOC_G_CTRL:
- return v4l2_subdev_g_ctrl(sd, arg);
+ return v4l2_g_ctrl(sd->ctrl_handler, arg);
case VIDIOC_S_CTRL:
- return v4l2_subdev_s_ctrl(sd, arg);
+ return v4l2_s_ctrl(sd->ctrl_handler, arg);
case VIDIOC_G_EXT_CTRLS:
- return v4l2_subdev_g_ext_ctrls(sd, arg);
+ return v4l2_g_ext_ctrls(sd->ctrl_handler, arg);
case VIDIOC_S_EXT_CTRLS:
- return v4l2_subdev_s_ext_ctrls(sd, arg);
+ return v4l2_s_ext_ctrls(sd->ctrl_handler, arg);
case VIDIOC_TRY_EXT_CTRLS:
- return v4l2_subdev_try_ext_ctrls(sd, arg);
+ return v4l2_try_ext_ctrls(sd->ctrl_handler, arg);
case VIDIOC_DQEVENT:
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 8c780c2d937b..85d3048c1d67 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -29,6 +29,7 @@
#include "via-camera.h"
+MODULE_ALIAS("platform:viafb-camera");
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index c4742fc15529..c9691115f2d2 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -300,7 +300,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
retval = remap_pfn_range(vma, vma->vm_start,
- PFN_DOWN(virt_to_phys(mem->vaddr)),
+ mem->dma_handle >> PAGE_SHIFT,
size, vma->vm_page_prot);
if (retval) {
dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 6698c77e0f64..6ba1461d51ef 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -37,6 +37,9 @@ module_param(debug, int, 0644);
#define call_qop(q, op, args...) \
(((q)->ops->op) ? ((q)->ops->op(args)) : 0)
+#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
+ V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR)
+
/**
* __vb2_buf_mem_alloc() - allocate video memory for the given buffer
*/
@@ -51,7 +54,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb,
for (plane = 0; plane < vb->num_planes; ++plane) {
mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane],
plane_sizes[plane]);
- if (!mem_priv)
+ if (IS_ERR_OR_NULL(mem_priv))
goto free;
/* Associate allocator private data with this plane */
@@ -284,7 +287,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
struct vb2_queue *q = vb->vb2_queue;
int ret = 0;
- /* Copy back data such as timestamp, input, etc. */
+ /* Copy back data such as timestamp, flags, input, etc. */
memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
b->input = vb->v4l2_buf.input;
b->reserved = vb->v4l2_buf.reserved;
@@ -313,7 +316,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
b->m.userptr = vb->v4l2_planes[0].m.userptr;
}
- b->flags = 0;
+ /*
+ * Clear any buffer state related flags.
+ */
+ b->flags &= ~V4L2_BUFFER_STATE_FLAGS;
switch (vb->state) {
case VB2_BUF_STATE_QUEUED:
@@ -519,6 +525,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
memset(plane_sizes, 0, sizeof(plane_sizes));
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
+ q->memory = req->memory;
/*
* Ask the driver how many buffers and planes per buffer it requires.
@@ -560,8 +567,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
ret = num_buffers;
}
- q->memory = req->memory;
-
/*
* Return the number of successfully allocated buffers
* to the userspace.
@@ -715,6 +720,8 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b,
vb->v4l2_buf.field = b->field;
vb->v4l2_buf.timestamp = b->timestamp;
+ vb->v4l2_buf.input = b->input;
+ vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
return 0;
}
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c
index 58205d596138..a790a5f8c06f 100644
--- a/drivers/media/video/videobuf2-dma-contig.c
+++ b/drivers/media/video/videobuf2-dma-contig.c
@@ -46,7 +46,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
GFP_KERNEL);
if (!buf->vaddr) {
dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
- buf->size);
+ size);
kfree(buf);
return ERR_PTR(-ENOMEM);
}
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 75301d10a838..ca372eb911d0 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -354,7 +354,7 @@ static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* Here we back up the input selection because it gets
overwritten when we fill the registers with the
- choosen video norm */
+ chosen video norm */
temp_input = vpx3220_fp_read(sd, 0xf2);
v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std);
diff --git a/drivers/media/video/zoran/videocodec.h b/drivers/media/video/zoran/videocodec.h
index b654bfff8740..def55585ad23 100644
--- a/drivers/media/video/zoran/videocodec.h
+++ b/drivers/media/video/zoran/videocodec.h
@@ -57,7 +57,7 @@
therfor they may not be initialized.
The other functions are just for convenience, as they are for sure used by
- most/all of the codecs. The last ones may be ommited, too.
+ most/all of the codecs. The last ones may be omitted, too.
See the structure declaration below for more information and which data has
to be set up for the master and the slave.
diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
index 4bb368e6fd47..f3f640014928 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/video/zoran/zoran.h
@@ -259,7 +259,7 @@ struct card_info {
struct vfe_polarity vfe_pol;
u8 gpio_pol[ZR_GPIO_MAX];
- /* is the /GWS line conected? */
+ /* is the /GWS line connected? */
u8 gws_not_connected;
/* avs6eyes mux setting */
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 9f2bac519647..79b04ac0f1ad 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -64,14 +64,6 @@ static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "Card type");
-static int encoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
-module_param_array(encoder, int, NULL, 0444);
-MODULE_PARM_DESC(encoder, "Video encoder chip");
-
-static int decoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
-module_param_array(decoder, int, NULL, 0444);
-MODULE_PARM_DESC(decoder, "Video decoder chip");
-
/*
The video mem address of the video card.
The driver has a little database for some videocards
@@ -1230,7 +1222,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
mutex_init(&zr->other_lock);
if (pci_enable_device(pdev))
goto zr_unreg;
- pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
+ zr->revision = zr->pci_dev->revision;
dprintk(1,
KERN_INFO
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 7c3921de9589..2771d818406e 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -1254,7 +1254,7 @@ static int setup_overlay(struct zoran_fh *fh, int on)
{
struct zoran *zr = fh->zr;
- /* If there is nothing to do, return immediatly */
+ /* If there is nothing to do, return immediately */
if ((on && fh->overlay_active != ZORAN_FREE) ||
(!on && fh->overlay_active == ZORAN_FREE))
return 0;