summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/Kconfig29
-rw-r--r--linux/drivers/media/video/Makefile7
-rw-r--r--linux/drivers/media/video/arv.c12
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-cards.c70
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c1
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-risc.c3
-rw-r--r--linux/drivers/media/video/bt8xx/bttvp.h5
-rw-r--r--linux/drivers/media/video/btcx-risc.c6
-rw-r--r--linux/drivers/media/video/btcx-risc.h2
-rw-r--r--linux/drivers/media/video/bw-qcam.c4
-rw-r--r--linux/drivers/media/video/cpia2/cpia2_v4l.c1
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-firmware.c16
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c6
-rw-r--r--linux/drivers/media/video/cx18/cx18-irq.c2
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.c31
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.h2
-rw-r--r--linux/drivers/media/video/cx2341x.c5
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c46
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c76
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h1
-rw-r--r--linux/drivers/media/video/dpc7146.c409
-rw-r--r--linux/drivers/media/video/gspca/conex.c4
-rw-r--r--linux/drivers/media/video/gspca/etoms.c8
-rw-r--r--linux/drivers/media/video/gspca/gspca.c39
-rw-r--r--linux/drivers/media/video/gspca/gspca.h12
-rw-r--r--linux/drivers/media/video/gspca/mars.c4
-rw-r--r--linux/drivers/media/video/gspca/ov519.c4
-rw-r--r--linux/drivers/media/video/gspca/pac207.c5
-rw-r--r--linux/drivers/media/video/gspca/pac7311.c863
-rw-r--r--linux/drivers/media/video/gspca/sonixb.c4
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c449
-rw-r--r--linux/drivers/media/video/gspca/spca500.c4
-rw-r--r--linux/drivers/media/video/gspca/spca501.c4
-rw-r--r--linux/drivers/media/video/gspca/spca505.c4
-rw-r--r--linux/drivers/media/video/gspca/spca506.c4
-rw-r--r--linux/drivers/media/video/gspca/spca508.c4
-rw-r--r--linux/drivers/media/video/gspca/spca561.c658
-rw-r--r--linux/drivers/media/video/gspca/stk014.c4
-rw-r--r--linux/drivers/media/video/gspca/sunplus.c4
-rw-r--r--linux/drivers/media/video/gspca/t613.c8
-rw-r--r--linux/drivers/media/video/gspca/tv8532.c4
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c4
-rw-r--r--linux/drivers/media/video/gspca/zc3xx.c52
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.h1
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-irq.c29
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-queue.h2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-vbi.c4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--linux/drivers/media/video/ks0127.c31
-rw-r--r--linux/drivers/media/video/meye.c4
-rw-r--r--linux/drivers/media/video/mt9m001.c55
-rw-r--r--linux/drivers/media/video/mt9m111.c981
-rw-r--r--linux/drivers/media/video/mt9v022.c52
-rw-r--r--linux/drivers/media/video/mxb.c25
-rw-r--r--linux/drivers/media/video/ov511.c14
-rw-r--r--linux/drivers/media/video/pms.c13
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c3
-rw-r--r--linux/drivers/media/video/pwc/pwc-ctrl.c18
-rw-r--r--linux/drivers/media/video/pxa_camera.c29
-rw-r--r--linux/drivers/media/video/s2255drv.c535
-rw-r--r--linux/drivers/media/video/saa7134/saa6752hs.c322
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c54
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c22
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c5
-rw-r--r--linux/drivers/media/video/tda9840.c170
-rw-r--r--linux/drivers/media/video/tea6415c.c135
-rw-r--r--linux/drivers/media/video/tea6420.c151
-rw-r--r--linux/drivers/media/video/tuner-3036.c215
-rw-r--r--linux/drivers/media/video/usbvideo/ibmcam.c6
-rw-r--r--linux/drivers/media/video/usbvideo/usbvideo.c7
-rw-r--r--linux/drivers/media/video/uvc/uvc_driver.c15
-rw-r--r--linux/drivers/media/video/uvc/uvc_video.c2
-rw-r--r--linux/drivers/media/video/v4l2-common.c183
-rw-r--r--linux/drivers/media/video/v4l2-dev.c7
-rw-r--r--linux/drivers/media/video/v4l2-ioctl.c4
-rw-r--r--linux/drivers/media/video/vino.c6
-rw-r--r--linux/drivers/media/video/vivi.c44
-rw-r--r--linux/drivers/media/video/zoran_device.c4
-rw-r--r--linux/drivers/media/video/zoran_procfs.c3
-rw-r--r--linux/drivers/media/video/zr364xx.c41
82 files changed, 3695 insertions, 2383 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index d6b1a106a..7b2925808 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -34,6 +34,7 @@ config VIDEOBUF_DVB
select VIDEOBUF_GEN
config VIDEO_BTCX
+ depends on PCI
tristate
config VIDEO_IR
@@ -578,13 +579,6 @@ config VIDEO_SAA5249
To compile this driver as a module, choose M here: the
module will be called saa5249.
-config TUNER_3036
- tristate "SAB3036 tuner"
- depends on I2C && VIDEO_V4L1
- help
- Say Y here to include support for Philips SAB3036 compatible tuners.
- If in doubt, say N.
-
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -708,21 +702,6 @@ config VIDEO_MXB
To compile this driver as a module, choose M here: the
module will be called mxb.
-config VIDEO_DPC
- tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
- depends on PCI && VIDEO_V4L1 && I2C
- select VIDEO_SAA7146_VV
- select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
- ---help---
- This is a video4linux driver for the 'dpc7146 demonstration
- board' by Philips-Semiconductors. It's the reference design
- for SAA7146 bases boards, so if you have some unsupported
- saa7146 based, analog video card, chances are good that it
- will work with this skeleton driver.
-
- To compile this driver as a module, choose M here: the
- module will be called dpc7146.
-
config VIDEO_HEXIUM_ORION
tristate "Hexium HV-PCI6 and Orion frame grabber"
depends on PCI && VIDEO_V4L2 && I2C
@@ -808,6 +787,12 @@ config MT9M001_PCA9536_SWITCH
Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
extender to switch between 8 and 10 bit datawidth modes
+config SOC_CAMERA_MT9M111
+ tristate "mt9m111 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports MT9M111 cameras from Micron
+
config SOC_CAMERA_MT9V022
tristate "mt9v022 support"
depends on SOC_CAMERA && I2C
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index bf429b023..bcd23e3cb 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -20,6 +20,8 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
endif
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
@@ -83,10 +85,6 @@ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
-obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
-obj-$(CONFIG_TUNER_3036) += tuner-3036.o
-
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -138,6 +136,7 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
diff --git a/linux/drivers/media/video/arv.c b/linux/drivers/media/video/arv.c
index e100d4cfb..9e96e7773 100644
--- a/linux/drivers/media/video/arv.c
+++ b/linux/drivers/media/video/arv.c
@@ -39,7 +39,7 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
-#if 0 /* keep */;
+#if 0 /* keep */
#define DEBUG(n, args...) printk(args)
#define CHECK_LOST 1
#else
@@ -579,11 +579,11 @@ static void ar_interrupt(int irq, void *dev)
* we have to start capture.
*/
disable_dma();
-#if 0 /* keep */;
+#if 0 /* keep */
ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* needless? */
#endif
memcpy(ar->frame[0], ar->line_buff, ar->line_bytes);
-#if 0 /* keep */;
+#if 0 /* keep */
ar_outl(0xa1861300, M32R_DMA0CR0_PORTL);
#endif
enable_dma();
@@ -609,7 +609,7 @@ static void ar_interrupt(int irq, void *dev)
ar_outl(arvcr1, ARVCR1); /* disable */
wake_up_interruptible(&ar->wait);
} else {
-#if 0 /* keep */;
+#if 0 /* keep */
ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL);
ar_outl(0xa1861300, M32R_DMA0CR0_PORTL);
#endif
@@ -693,7 +693,7 @@ static int ar_initialize(struct video_device *dev)
printk(".");
iic(2,0x78,0x8e,0x0c,0x00);
iic(2,0x78,0x8f,0x00,0x00);
-#if 0 /* keep */;
+#if 0 /* keep */
iic(2,0x78,0x90,0x00,0x00); /* AWB on=1 off=0 */
#endif
iic(2,0x78,0x93,0x01,0x00);
@@ -712,7 +712,7 @@ static int ar_initialize(struct video_device *dev)
iic(2,0x78,0x9e,0x2e,0x00);
iic(2,0x78,0xb8,0x78,0x00);
iic(2,0x78,0xba,0x05,0x00);
-#if 0 /* keep */;
+#if 0 /* keep */
iic(2,0x78,0x83,0x8c,0x00); /* brightness */
#endif
printk(".");
diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c
index bf3339436..9c4e77393 100644
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c
@@ -3201,8 +3201,9 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
static void flyvideo_gpio(struct bttv *btv)
{
- int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
- int tuner=UNSET,ttype;
+ int gpio, has_remote, has_radio, is_capture_only;
+ int is_lr90, has_tda9820_tda9821;
+ int tuner_type = UNSET, ttype;
gpio_inout(0xffffff, 0);
udelay(8); /* without this we would see the 0x1800 mask */
@@ -3220,20 +3221,26 @@ static void flyvideo_gpio(struct bttv *btv)
* xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
* Note: Some bits are Audio_Mask !
*/
- ttype=(gpio&0x0f0000)>>16;
- switch(ttype) {
- case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
+ ttype = (gpio & 0x0f0000) >> 16;
+ switch (ttype) {
+ case 0x0:
+ tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */
break;
- case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+ case 0x2:
+ tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */
break;
- case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
+ case 0x4:
+ tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
break;
- case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */
+ case 0x6:
+ tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */
break;
- case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
+ case 0xC:
+ tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
break;
default:
printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr);
+ break;
}
has_remote = gpio & 0x800000;
@@ -3246,23 +3253,26 @@ static void flyvideo_gpio(struct bttv *btv)
/*
* gpio & 0x001000 output bit for audio routing */
- if(is_capture_only)
- tuner = TUNER_ABSENT; /* No tuner present */
+ if (is_capture_only)
+ tuner_type = TUNER_ABSENT; /* No tuner present */
printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
- btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
+ btv->c.nr, has_radio ? "yes" : "no ",
+ has_remote ? "yes" : "no ", tuner_type, gpio);
printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n",
- btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
- is_capture_only?"yes":"no ");
+ btv->c.nr, is_lr90 ? "yes" : "no ",
+ has_tda9820_tda9821 ? "yes" : "no ",
+ is_capture_only ? "yes" : "no ");
- if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
- btv->tuner_type = tuner;
+ if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */
+ btv->tuner_type = tuner_type;
btv->has_radio = has_radio;
/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
* LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
* Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
- if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
+ if (has_tda9820_tda9821)
+ btv->audio_mode_gpio = lt9415_audio;
/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
}
@@ -4036,7 +4046,7 @@ static int tuner_1_table[] = {
static void __devinit avermedia_eeprom(struct bttv *btv)
{
- int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+ int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0;
tuner_make = (eeprom_data[0x41] & 0x7);
tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
@@ -4044,24 +4054,24 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
btv->has_remote = (eeprom_data[0x42] & 0x01);
if (tuner_make == 0 || tuner_make == 2)
- if(tuner_format <=0x0a)
- tuner = tuner_0_table[tuner_format];
+ if (tuner_format <= 0x0a)
+ tuner_type = tuner_0_table[tuner_format];
if (tuner_make == 1)
- if(tuner_format <=9)
- tuner = tuner_1_table[tuner_format];
+ if (tuner_format <= 9)
+ tuner_type = tuner_1_table[tuner_format];
if (tuner_make == 4)
- if(tuner_format == 0x09)
- tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
+ if (tuner_format == 0x09)
+ tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
- btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]);
- if(tuner) {
- btv->tuner_type=tuner;
- printk("%d",tuner);
+ btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]);
+ if (tuner_type) {
+ btv->tuner_type = tuner_type;
+ printk(KERN_CONT "%d", tuner_type);
} else
- printk("Unknown type");
- printk(" radio:%s remote control:%s\n",
+ printk(KERN_CONT "Unknown type");
+ printk(KERN_CONT " radio:%s remote control:%s\n",
tuner_tv_fm ? "yes" : "no",
btv->has_remote ? "yes" : "no");
}
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index 012eeba5e..a111df094 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -96,7 +96,6 @@ static unsigned int irq_iswitch;
static unsigned int uv_ratio = 50;
static unsigned int full_luma_range;
static unsigned int coring;
-extern int no_overlay;
/* API features (turn on/off stuff for testing) */
static unsigned int v4l2 = 1;
diff --git a/linux/drivers/media/video/bt8xx/bttv-risc.c b/linux/drivers/media/video/bt8xx/bttv-risc.c
index 0cffd3a72..310924f77 100644
--- a/linux/drivers/media/video/bt8xx/bttv-risc.c
+++ b/linux/drivers/media/video/bt8xx/bttv-risc.c
@@ -244,7 +244,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
const struct bttv_format *fmt, struct bttv_overlay *ov,
int skip_even, int skip_odd)
{
- int dwords,rc,line,maxy,start,end,skip,nskips;
+ int dwords, rc, line, maxy, start, end;
+ unsigned skip, nskips;
struct btcx_skiplist *skips;
__le32 *rp;
u32 ri,ra;
diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h
index 63d1d4451..403695f9a 100644
--- a/linux/drivers/media/video/bt8xx/bttvp.h
+++ b/linux/drivers/media/video/bt8xx/bttvp.h
@@ -269,6 +269,11 @@ int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
/* ---------------------------------------------------------- */
+/* bttv-cards.c */
+
+extern int no_overlay;
+
+/* ---------------------------------------------------------- */
/* bttv-driver.c */
/* insmod options */
diff --git a/linux/drivers/media/video/btcx-risc.c b/linux/drivers/media/video/btcx-risc.c
index e0e1158ce..1c2413571 100644
--- a/linux/drivers/media/video/btcx-risc.c
+++ b/linux/drivers/media/video/btcx-risc.c
@@ -65,7 +65,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
unsigned int size)
{
__le32 *cpu;
- dma_addr_t dma;
+ dma_addr_t dma = 0;
if (NULL != risc->cpu && risc->size < size)
btcx_riscmem_free(pci,risc);
@@ -185,12 +185,12 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
}
void
-btcx_calc_skips(int line, int width, unsigned int *maxy,
+btcx_calc_skips(int line, int width, int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips)
{
unsigned int clip,skip;
- int end,maxline;
+ int end, maxline;
skip=0;
maxline = 9999;
diff --git a/linux/drivers/media/video/btcx-risc.h b/linux/drivers/media/video/btcx-risc.h
index 861bc8112..f8bc6e8e7 100644
--- a/linux/drivers/media/video/btcx-risc.h
+++ b/linux/drivers/media/video/btcx-risc.h
@@ -23,7 +23,7 @@ int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
unsigned int n, int mask);
void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
-void btcx_calc_skips(int line, int width, unsigned int *maxy,
+void btcx_calc_skips(int line, int width, int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips);
diff --git a/linux/drivers/media/video/bw-qcam.c b/linux/drivers/media/video/bw-qcam.c
index df2b25b69..393113875 100644
--- a/linux/drivers/media/video/bw-qcam.c
+++ b/linux/drivers/media/video/bw-qcam.c
@@ -496,7 +496,7 @@ static void qc_set(struct qcam_device *q)
val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
q->transfer_scale;
}
- val = (val + val2 - 1) / val2;
+ val = DIV_ROUND_UP(val, val2);
qc_command(q, 0x13);
qc_command(q, val);
@@ -652,7 +652,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
transperline = q->width * q->bpp;
divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
q->transfer_scale;
- transperline = (transperline + divisor - 1) / divisor;
+ transperline = DIV_ROUND_UP(transperline, divisor);
for (i = 0, yield = yieldlines; i < linestotrans; i++)
{
diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c
index 515c8b57a..c82570606 100644
--- a/linux/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1024,7 +1024,6 @@ static int ioctl_queryctrl(void *arg,struct camera_data *cam)
if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
// Maximum 15fps
- int i;
for(i=0; i<c->maximum; ++i) {
if(framerate_controls[i].value ==
CPIA2_VP_FRAMERATE_15) {
diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c
index 834b92482..e996a4e31 100644
--- a/linux/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c
@@ -32,7 +32,7 @@ int cx18_av_loadfw(struct cx18 *cx)
u32 v;
const u8 *ptr;
int i;
- int retries = 0;
+ int retries1 = 0;
if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
CX18_ERR("unable to open firmware %s\n", FWFILE);
@@ -41,7 +41,7 @@ int cx18_av_loadfw(struct cx18 *cx)
/* The firmware load often has byte errors, so allow for several
retries, both at byte level and at the firmware load level. */
- while (retries < 5) {
+ while (retries1 < 5) {
cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
@@ -57,9 +57,9 @@ int cx18_av_loadfw(struct cx18 *cx)
for (i = 0; i < size; i++) {
u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
u32 value = 0;
- int retries;
+ int retries2;
- for (retries = 0; retries < 5; retries++) {
+ for (retries2 = 0; retries2 < 5; retries2++) {
cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
udelay(10);
value = cx18_av_read4(cx, CXADEC_DL_CTL);
@@ -69,18 +69,18 @@ int cx18_av_loadfw(struct cx18 *cx)
the address. We can only write the lower
address byte of the address. */
if ((value & 0x3F00) != (dl_control & 0x3F00)) {
- retries = 5;
+ retries2 = 5;
break;
}
}
- if (retries >= 5)
+ if (retries2 >= 5)
break;
}
if (i == size)
break;
- retries++;
+ retries1++;
}
- if (retries >= 5) {
+ if (retries1 >= 5) {
CX18_ERR("unable to load firmware %s\n", FWFILE);
release_firmware(fw);
return -EIO;
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index 22434aadd..bd18afebb 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -74,9 +74,9 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
-static int cardtype_c = 1;
-static int tuner_c = 1;
-static int radio_c = 1;
+static unsigned cardtype_c = 1;
+static unsigned tuner_c = 1;
+static unsigned radio_c = 1;
static char pal[] = "--";
static char secam[] = "--";
static char ntsc[] = "-";
diff --git a/linux/drivers/media/video/cx18/cx18-irq.c b/linux/drivers/media/video/cx18/cx18-irq.c
index 654664783..b9cf609ee 100644
--- a/linux/drivers/media/video/cx18/cx18-irq.c
+++ b/linux/drivers/media/video/cx18/cx18-irq.c
@@ -61,7 +61,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
CX18_WARN("Ack struct = %d for %s\n",
mb->args[2], s->name);
id = read_enc(off);
- buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
+ buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4));
CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
if (buf) {
cx18_buf_sync_for_cpu(s, buf);
diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c
index 6990b77c6..a31da49f9 100644
--- a/linux/drivers/media/video/cx18/cx18-queue.c
+++ b/linux/drivers/media/video/cx18/cx18-queue.c
@@ -78,12 +78,13 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
return buf;
}
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
u32 bytesused)
{
struct cx18 *cx = s->cx;
struct list_head *p;
+ spin_lock(&s->qlock);
list_for_each(p, &s->q_free.list) {
struct cx18_buffer *buf =
list_entry(p, struct cx18_buffer, list);
@@ -92,17 +93,19 @@ struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
continue;
buf->bytesused = bytesused;
/* the transport buffers are handled differently,
- so there is no need to move them to the full queue */
- if (s->type == CX18_ENC_STREAM_TYPE_TS)
- return buf;
- s->q_free.buffers--;
- s->q_free.length -= s->buf_size;
- s->q_full.buffers++;
- s->q_full.length += s->buf_size;
- s->q_full.bytesused += buf->bytesused;
- list_move_tail(&buf->list, &s->q_full.list);
+ they are not moved to the full queue */
+ if (s->type != CX18_ENC_STREAM_TYPE_TS) {
+ s->q_free.buffers--;
+ s->q_free.length -= s->buf_size;
+ s->q_full.buffers++;
+ s->q_full.length += s->buf_size;
+ s->q_full.bytesused += buf->bytesused;
+ list_move_tail(&buf->list, &s->q_full.list);
+ }
+ spin_unlock(&s->qlock);
return buf;
}
+ spin_unlock(&s->qlock);
CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
return NULL;
}
@@ -214,10 +217,10 @@ int cx18_stream_alloc(struct cx18_stream *s)
s->name, s->buffers, s->buf_size,
s->buffers * s->buf_size / 1024);
- if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
- (char *)cx->scb) > SCB_RESERVED_SIZE) {
- unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
- ((char *)cx->scb->cpu_mdl));
+ if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+ (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
+ unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE -
+ ((char __iomem *)cx->scb->cpu_mdl));
CX18_ERR("Too many buffers, cannot fit in SCB area\n");
CX18_ERR("Max buffers = %zd\n",
diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h
index 91423b986..7f93bb13c 100644
--- a/linux/drivers/media/video/cx18/cx18-queue.h
+++ b/linux/drivers/media/video/cx18/cx18-queue.h
@@ -46,7 +46,7 @@ void cx18_queue_init(struct cx18_queue *q);
void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
struct cx18_queue *q);
struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
u32 bytesused);
void cx18_flush_queues(struct cx18_stream *s);
diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c
index 835062f5b..f31f11e3f 100644
--- a/linux/drivers/media/video/cx2341x.c
+++ b/linux/drivers/media/video/cx2341x.c
@@ -509,7 +509,10 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
/* this setting is read-only for the cx2341x since the
V4L2_CID_MPEG_STREAM_TYPE really determines the
MPEG-1/2 setting */
- err = v4l2_ctrl_query_fill_std(qctrl);
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
if (err == 0)
qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
return err;
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index ee01ff8bf..f7cb19256 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -27,6 +27,7 @@
#include "compat.h"
#include "cx23885.h"
+#include "tuner-xc2028.h"
/* ------------------------------------------------------------------ */
/* board config info */
@@ -149,6 +150,11 @@ struct cx23885_board cx23885_boards[] = {
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = {
+ .name = "DViCO FusionHDTV DVB-T Dual Express",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -220,6 +226,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x18ac,
.subdevice = 0xd618,
.card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb78,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -320,15 +330,15 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
dev->name, tv.model);
}
-/* Tuner callback function for cx23885 boards. Currently only needed
- * for HVR1500Q, which has an xc5000 tuner.
- */
int cx23885_tuner_callback(void *priv, int command, int arg)
{
- struct cx23885_i2c *bus = priv;
- struct cx23885_dev *dev = bus->dev;
+ struct cx23885_tsport *port = priv;
+ struct cx23885_dev *dev = port->dev;
u32 bitmask = 0;
+ if (command == XC2028_RESET_CLK)
+ return 0;
+
if (command != 0) {
printk(KERN_ERR "%s(): Unknown command 0x%x.\n",
__func__, command);
@@ -336,19 +346,22 @@ int cx23885_tuner_callback(void *priv, int command, int arg)
}
switch(dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- /* Tuner Reset Command from xc5000 */
+ /* Tuner Reset Command */
if (command == 0)
bitmask = 0x04;
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
if (command == 0) {
/* Two identical tuners on two different i2c buses,
* we need to reset the correct gpio. */
- if (bus->nr == 0)
+ if (port->nr == 0)
bitmask = 0x01;
- else if (bus->nr == 1)
+ else if (port->nr == 1)
bitmask = 0x04;
}
break;
@@ -466,6 +479,19 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
mdelay(20);
cx_set(GP0_IO, 0x000f000f);
break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ /* GPIO-0 portb xc3028 reset */
+ /* GPIO-1 portb zl10353 reset */
+ /* GPIO-2 portc xc3028 reset */
+ /* GPIO-3 portc zl10353 reset */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x000f0000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x0000000f);
+ mdelay(20);
+ cx_set(GP0_IO, 0x000f000f);
+ break;
}
}
@@ -480,6 +506,9 @@ int cx23885_ir_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1400:
/* FIXME: Implement me */
break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ request_module("ir-kbd-i2c");
+ break;
}
return 0;
@@ -517,6 +546,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
switch (dev->board) {
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 3c01ef2bf..c0c5b5be7 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -43,6 +43,7 @@
#include "tuner-simple.h"
#include "dib7000p.h"
#include "dibx000_common.h"
+#include "zl10353.h"
static unsigned int debug;
@@ -189,13 +190,13 @@ static struct s5h1411_config dvico_s5h1411_config = {
static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
.i2c_address = 0x61,
.if_khz = 5380,
- .tuner_callback = cx23885_tuner_callback
+ .tuner_callback = cx23885_tuner_callback,
};
static struct xc5000_config dvico_xc5000_tunerconfig = {
.i2c_address = 0x64,
.if_khz = 5380,
- .tuner_callback = cx23885_tuner_callback
+ .tuner_callback = cx23885_tuner_callback,
};
static struct tda829x_config tda829x_no_probe = {
@@ -304,35 +305,11 @@ static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
.output_mode = OUTMODE_MPEG2_SERIAL,
};
-static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
-{
- struct cx23885_tsport *port = ptr;
- struct cx23885_dev *dev = port->dev;
-
- switch (command) {
- case XC2028_TUNER_RESET:
- /* Send the tuner in then out of reset */
- /* GPIO-2 xc3028 tuner */
- dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
-
- cx_set(GP0_IO, 0x00040000);
- cx_clear(GP0_IO, 0x00000004);
- msleep(5);
-
- cx_set(GP0_IO, 0x00040004);
- msleep(5);
- break;
- case XC2028_RESET_CLK:
- dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
- break;
- default:
- dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
- command, arg);
- return -EINVAL;
- }
-
- return 0;
-}
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+ .demod_address = 0x0f,
+ .if2 = 45600,
+ .no_tuner = 1,
+};
static int dvb_register(struct cx23885_tsport *port)
{
@@ -415,7 +392,7 @@ static int dvb_register(struct cx23885_tsport *port)
if (port->dvb.frontend != NULL)
dvb_attach(xc5000_attach, port->dvb.frontend,
&i2c_bus->i2c_adap,
- &hauppauge_hvr1500q_tunerconfig, i2c_bus);
+ &hauppauge_hvr1500q_tunerconfig, port);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500:
i2c_bus = &dev->i2c_bus[1];
@@ -427,7 +404,8 @@ static int dvb_register(struct cx23885_tsport *port)
struct xc2028_config cfg = {
.i2c_adap = &i2c_bus->i2c_adap,
.i2c_addr = 0x61,
- .callback = cx23885_hvr1500_xc3028_callback,
+ .video_dev = port,
+ .callback = cx23885_tuner_callback,
};
static struct xc2028_ctrl ctl = {
.fname = "xc3028-v27.fw",
@@ -466,7 +444,8 @@ static int dvb_register(struct cx23885_tsport *port)
struct xc2028_config cfg = {
.i2c_adap = &dev->i2c_bus[1].i2c_adap,
.i2c_addr = 0x64,
- .callback = cx23885_hvr1500_xc3028_callback,
+ .video_dev = port,
+ .callback = cx23885_tuner_callback,
};
static struct xc2028_ctrl ctl = {
.fname = "xc3028L-v36.fw",
@@ -494,8 +473,35 @@ static int dvb_register(struct cx23885_tsport *port)
if (port->dvb.frontend != NULL)
dvb_attach(xc5000_attach, port->dvb.frontend,
&i2c_bus->i2c_adap,
- &dvico_xc5000_tunerconfig, i2c_bus);
+ &dvico_xc5000_tunerconfig, port);
break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
+ i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+ port->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_xc3028,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &i2c_bus->i2c_adap,
+ .i2c_addr = 0x61,
+ .video_dev = port,
+ .callback = cx23885_tuner_callback,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = "xc3028-v27.fw",
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ };
+
+ fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+ &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ }
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->name);
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index 9a0b4bf3a..9b76a8acf 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -65,6 +65,7 @@
#define CX23885_BOARD_HAUPPAUGE_HVR1700 8
#define CX23885_BOARD_HAUPPAUGE_HVR1400 9
#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
+#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
diff --git a/linux/drivers/media/video/dpc7146.c b/linux/drivers/media/video/dpc7146.c
deleted file mode 100644
index 4bfb3076b..000000000
--- a/linux/drivers/media/video/dpc7146.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- dpc7146.c - v4l2 driver for the dpc7146 demonstration board
-
- Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#define DEBUG_VARIABLE debug
-
-#include <media/saa7146_vv.h>
-#include <linux/video_decoder.h> /* for saa7111a */
-#include "compat.h"
-
-#define I2C_SAA7111A 0x24
-
-/* All unused bytes are reserverd. */
-#define SAA711X_CHIP_VERSION 0x00
-#define SAA711X_ANALOG_INPUT_CONTROL_1 0x02
-#define SAA711X_ANALOG_INPUT_CONTROL_2 0x03
-#define SAA711X_ANALOG_INPUT_CONTROL_3 0x04
-#define SAA711X_ANALOG_INPUT_CONTROL_4 0x05
-#define SAA711X_HORIZONTAL_SYNC_START 0x06
-#define SAA711X_HORIZONTAL_SYNC_STOP 0x07
-#define SAA711X_SYNC_CONTROL 0x08
-#define SAA711X_LUMINANCE_CONTROL 0x09
-#define SAA711X_LUMINANCE_BRIGHTNESS 0x0A
-#define SAA711X_LUMINANCE_CONTRAST 0x0B
-#define SAA711X_CHROMA_SATURATION 0x0C
-#define SAA711X_CHROMA_HUE_CONTROL 0x0D
-#define SAA711X_CHROMA_CONTROL 0x0E
-#define SAA711X_FORMAT_DELAY_CONTROL 0x10
-#define SAA711X_OUTPUT_CONTROL_1 0x11
-#define SAA711X_OUTPUT_CONTROL_2 0x12
-#define SAA711X_OUTPUT_CONTROL_3 0x13
-#define SAA711X_V_GATE_1_START 0x15
-#define SAA711X_V_GATE_1_STOP 0x16
-#define SAA711X_V_GATE_1_MSB 0x17
-#define SAA711X_TEXT_SLICER_STATUS 0x1A
-#define SAA711X_DECODED_BYTES_OF_TS_1 0x1B
-#define SAA711X_DECODED_BYTES_OF_TS_2 0x1C
-#define SAA711X_STATUS_BYTE 0x1F
-
-#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
-
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "debug verbosity");
-
-static int dpc_num;
-
-#define DPC_INPUTS 2
-static struct v4l2_input dpc_inputs[DPC_INPUTS] = {
- { 0, "Port A", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 1, "Port B", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-};
-
-#define DPC_AUDIOS 0
-
-static struct saa7146_extension_ioctls ioctls[] = {
- { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
- { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
- { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
- { VIDIOC_S_STD, SAA7146_AFTER },
- { 0, 0 }
-};
-
-struct dpc
-{
- struct video_device *video_dev;
- struct video_device *vbi_dev;
-
- struct i2c_adapter i2c_adapter;
- struct i2c_client *saa7111a;
-
- int cur_input; /* current input */
-};
-
-static int dpc_check_clients(struct device *dev, void *data)
-{
- struct dpc* dpc = data;
- struct i2c_client *client = i2c_verify_client(dev);
-
- if( !client )
- return 0;
-
- if( I2C_SAA7111A == client->addr )
- dpc->saa7111a = client;
-
- return 0;
-}
-
-/* fixme: add vbi stuff here */
-static int dpc_probe(struct saa7146_dev* dev)
-{
- struct dpc* dpc = NULL;
-
- dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
- if( NULL == dpc ) {
- printk("dpc_v4l2.o: dpc_probe: not enough kernel memory.\n");
- return -ENOMEM;
- }
-
- /* FIXME: enable i2c-port pins, video-port-pins
- video port pins should be enabled here ?! */
- saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
-
- dpc->i2c_adapter = (struct i2c_adapter) {
- .class = I2C_CLASS_TV_ANALOG,
- .name = "dpc7146",
- };
- saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
- if(i2c_add_adapter(&dpc->i2c_adapter) < 0) {
- DEB_S(("cannot register i2c-device. skipping.\n"));
- kfree(dpc);
- return -EFAULT;
- }
-
- /* loop through all i2c-devices on the bus and look who is there */
- device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
-
- /* check if all devices are present */
- if (!dpc->saa7111a) {
- DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
- i2c_del_adapter(&dpc->i2c_adapter);
- kfree(dpc);
- return -ENODEV;
- }
-
- /* all devices are present, probe was successful */
- DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
-
- /* we store the pointer in our private data field */
- dev->ext_priv = dpc;
-
- return 0;
-}
-
-/* bring hardware to a sane state. this has to be done, just in case someone
- wants to capture from this device before it has been properly initialized.
- the capture engine would badly fail, because no valid signal arrives on the
- saa7146, thus leading to timeouts and stuff. */
-static int dpc_init_done(struct saa7146_dev* dev)
-{
- struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
- DEB_D(("dpc_v4l2.o: dpc_init_done called.\n"));
-
- /* initialize the helper ics to useful values */
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x00, 0x11);
-
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x02, 0xc0);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x03, 0x30);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x04, 0x00);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x05, 0x00);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x06, 0xde);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x07, 0xad);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x08, 0xa8);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x09, 0x00);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x0a, 0x80);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x0b, 0x47);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x0c, 0x40);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x0d, 0x00);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x0e, 0x03);
-
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x10, 0xd0);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x11, 0x1c);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x12, 0xc1);
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x13, 0x30);
-
- i2c_smbus_write_byte_data(dpc->saa7111a, 0x1f, 0x81);
-
- return 0;
-}
-
-static struct saa7146_ext_vv vv_data;
-
-/* this function only gets called when the probing was successful */
-static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
-{
- struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
- DEB_D(("dpc_v4l2.o: dpc_attach called.\n"));
-
- /* checking for i2c-devices can be omitted here, because we
- already did this in "dpc_vl42_probe" */
-
- saa7146_vv_init(dev,&vv_data);
- if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) {
- ERR(("cannot register capture v4l2 device. skipping.\n"));
- return -1;
- }
-
- /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
- if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
- if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) {
- ERR(("cannot register vbi v4l2 device. skipping.\n"));
- }
- }
-
- i2c_use_client(dpc->saa7111a);
-
- printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num);
- dpc_num++;
-
- /* the rest */
- dpc->cur_input = 0;
- dpc_init_done(dev);
-
- return 0;
-}
-
-static int dpc_detach(struct saa7146_dev* dev)
-{
- struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
- DEB_EE(("dev:%p\n",dev));
-
- i2c_release_client(dpc->saa7111a);
-
- saa7146_unregister_device(&dpc->video_dev,dev);
- if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
- saa7146_unregister_device(&dpc->vbi_dev,dev);
- }
- saa7146_vv_release(dev);
-
- dpc_num--;
-
- i2c_del_adapter(&dpc->i2c_adapter);
- kfree(dpc);
- return 0;
-}
-
-#ifdef axa
-int dpc_vbi_bypass(struct saa7146_dev* dev)
-{
- struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
- int i = 1;
-
- /* switch bypass in saa7111a */
- if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) {
- printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n");
- return -1;
- }
-
- return 0;
-}
-#endif
-
-static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
-{
- struct saa7146_dev *dev = fh->dev;
- struct dpc* dpc = (struct dpc*)dev->ext_priv;
-/*
- struct saa7146_vv *vv = dev->vv_data;
-*/
- switch(cmd)
- {
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *i = arg;
- DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-
- if( i->index < 0 || i->index >= DPC_INPUTS) {
- return -EINVAL;
- }
-
- memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input));
-
- DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index));
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- int *input = (int *)arg;
- *input = dpc->cur_input;
-
- DEB_D(("dpc_v4l2.o: VIDIOC_G_INPUT: %d\n",*input));
- return 0;
- }
- case VIDIOC_S_INPUT:
- {
- int input = *(int *)arg;
-
- if (input < 0 || input >= DPC_INPUTS) {
- return -EINVAL;
- }
-
- dpc->cur_input = input;
-
- /* fixme: switch input here, switch audio, too! */
-// saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
- printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n");
-
- return 0;
- }
- default:
-/*
- DEB_D(("dpc_v4l2.o: v4l2_ioctl does not handle this ioctl.\n"));
-*/
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
-{
- return 0;
-}
-
-static struct saa7146_standard standard[] = {
- {
- .name = "PAL", .id = V4L2_STD_PAL,
- .v_offset = 0x17, .v_field = 288,
- .h_offset = 0x14, .h_pixels = 680,
- .v_max_out = 576, .h_max_out = 768,
- }, {
- .name = "NTSC", .id = V4L2_STD_NTSC,
- .v_offset = 0x16, .v_field = 240,
- .h_offset = 0x06, .h_pixels = 708,
- .v_max_out = 480, .h_max_out = 640,
- }, {
- .name = "SECAM", .id = V4L2_STD_SECAM,
- .v_offset = 0x14, .v_field = 288,
- .h_offset = 0x14, .h_pixels = 720,
- .v_max_out = 576, .h_max_out = 768,
- }
-};
-
-static struct saa7146_extension extension;
-
-static struct saa7146_pci_extension_data dpc = {
- .ext_priv = "Multimedia eXtension Board",
- .ext = &extension,
-};
-
-static struct pci_device_id pci_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
- .subvendor = 0x0000,
- .subdevice = 0x0000,
- .driver_data = (unsigned long)&dpc,
- }, {
- .vendor = 0,
- }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-static struct saa7146_ext_vv vv_data = {
- .inputs = DPC_INPUTS,
- .capabilities = V4L2_CAP_VBI_CAPTURE,
- .stds = &standard[0],
- .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
- .std_callback = &std_callback,
- .ioctls = &ioctls[0],
- .ioctl = dpc_ioctl,
-};
-
-static struct saa7146_extension extension = {
- .name = "dpc7146 demonstration board",
- .flags = SAA7146_USE_I2C_IRQ,
-
- .pci_tbl = &pci_tbl[0],
- .module = THIS_MODULE,
-
- .probe = dpc_probe,
- .attach = dpc_attach,
- .detach = dpc_detach,
-
- .irq_mask = 0,
- .irq_func = NULL,
-};
-
-static int __init dpc_init_module(void)
-{
- if( 0 != saa7146_register_extension(&extension)) {
- DEB_S(("failed to register extension.\n"));
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void __exit dpc_cleanup_module(void)
-{
- saa7146_unregister_extension(&extension);
-}
-
-module_init(dpc_init_module);
-module_exit(dpc_cleanup_module);
-
-MODULE_DESCRIPTION("video4linux-2 driver for the 'dpc7146 demonstration board'");
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c
index cd3a3f582..739ef557c 100644
--- a/linux/drivers/media/video/gspca/conex.c
+++ b/linux/drivers/media/video/gspca/conex.c
@@ -1026,6 +1026,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c
index 60b316a37..626d03e17 100644
--- a/linux/drivers/media/video/gspca/etoms.c
+++ b/linux/drivers/media/video/gspca/etoms.c
@@ -910,10 +910,10 @@ static struct sd_desc sd_desc = {
/* -- module initialisation -- */
static __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_ET61X251
{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
-#endif
+#ifndef CONFIG_USB_ET61X251
{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
+#endif
{}
};
@@ -932,6 +932,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index 61071a4f4..0d705af05 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -118,7 +118,8 @@ static void fill_frame(struct gspca_dev *gspca_dev,
cam_pkt_op pkt_scan;
if (urb->status != 0) {
- PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ if (!gspca_dev->frozen)
+ PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
return; /* disconnection ? */
}
pkt_scan = gspca_dev->sd_desc->pkt_scan;
@@ -857,6 +858,8 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
| V4L2_CAP_READWRITE;
+ if (gspca_dev->flags & GSPCA_SENSOR_UPSIDE_DOWN_FLAG)
+ cap->capabilities |= V4L2_CAP_SENSOR_UPSIDE_DOWN;
return 0;
}
@@ -890,11 +893,6 @@ static int vidioc_queryctrl(struct file *file, void *priv,
return 0;
}
}
- if (id >= V4L2_CID_BASE
- && id <= V4L2_CID_LASTP1) {
- q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
- return 0;
- }
return -EINVAL;
}
@@ -1410,7 +1408,7 @@ static int vidioc_dqbuf(struct file *file, void *priv,
i = ret; /* frame index */
frame = &gspca_dev->frame[i];
if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
- if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
+ if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
frame->data,
frame->v4l2_buf.bytesused)) {
PDEBUG(D_ERR|D_STREAM,
@@ -1815,6 +1813,33 @@ void gspca_disconnect(struct usb_interface *intf)
}
EXPORT_SYMBOL(gspca_disconnect);
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+ if (!gspca_dev->streaming)
+ return 0;
+ gspca_dev->frozen = 1; /* avoid urb error messages */
+ gspca_dev->sd_desc->stopN(gspca_dev);
+ destroy_urbs(gspca_dev);
+ gspca_set_alt0(gspca_dev);
+ gspca_dev->sd_desc->stop0(gspca_dev);
+ return 0;
+}
+EXPORT_SYMBOL(gspca_suspend);
+
+int gspca_resume(struct usb_interface *intf)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+ gspca_dev->frozen = 0;
+ if (!gspca_dev->streaming)
+ return 0;
+ return gspca_init_transfer(gspca_dev);
+}
+EXPORT_SYMBOL(gspca_resume);
+#endif
/* -- cam driver utility functions -- */
/* auto gain and exposure algorithm based on the knee algorithm described here:
diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h
index 67e448940..1920c99d6 100644
--- a/linux/drivers/media/video/gspca/gspca.h
+++ b/linux/drivers/media/video/gspca/gspca.h
@@ -56,7 +56,6 @@ extern int gspca_debug;
/* device information - set at probe time */
struct cam {
- char *dev_name;
struct v4l2_pix_format *cam_mode; /* size nmodes */
char nmodes;
__u8 epaddr;
@@ -119,6 +118,9 @@ struct gspca_frame {
struct v4l2_buffer v4l2_buf;
};
+/* defines for the flags member */
+#define GSPCA_SENSOR_UPSIDE_DOWN_FLAG 0x01
+
struct gspca_dev {
struct video_device vdev; /* !! must be the first item */
struct file_operations fops;
@@ -155,12 +157,16 @@ struct gspca_dev {
struct mutex queue_lock; /* ISOC queue protection */
__u32 sequence; /* frame sequence number */
char streaming;
+#ifdef CONFIG_PM
+ char frozen; /* suspend - resume */
+#endif
char users; /* number of opens */
char present; /* device connected */
char nbufread; /* number of buffers for read() */
char nurbs; /* number of allocated URBs */
char memory; /* memory type (V4L2_MEMORY_xxx) */
__u8 nbalt; /* number of USB alternate settings */
+ __u8 flags; /* see GSPCA_XXX_FLAG defines */
};
int gspca_dev_probe(struct usb_interface *intf,
@@ -174,6 +180,10 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
struct gspca_frame *frame,
const __u8 *data,
int len);
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message);
+int gspca_resume(struct usb_interface *intf);
+#endif
int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
#endif /* GSPCAV2_H */
diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c
index 21c4ee56a..d7e209578 100644
--- a/linux/drivers/media/video/gspca/mars.c
+++ b/linux/drivers/media/video/gspca/mars.c
@@ -439,6 +439,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c
index 2379433f0..e1c665b4d 100644
--- a/linux/drivers/media/video/gspca/ov519.c
+++ b/linux/drivers/media/video/gspca/ov519.c
@@ -2157,6 +2157,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c
index 7ef18d578..d9668f4cb 100644
--- a/linux/drivers/media/video/gspca/pac207.c
+++ b/linux/drivers/media/video/gspca/pac207.c
@@ -271,7 +271,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
cam = &gspca_dev->cam;
- cam->dev_name = (char *) id->driver_info;
cam->epaddr = 0x05;
cam->cam_mode = sif_mode;
cam->nmodes = ARRAY_SIZE(sif_mode);
@@ -597,6 +596,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c
index 1b3ea1e93..94f0cd1b8 100644
--- a/linux/drivers/media/video/gspca/pac7311.c
+++ b/linux/drivers/media/video/gspca/pac7311.c
@@ -22,6 +22,7 @@
#define MODULE_NAME "pac7311"
#include "gspca.h"
+#include "jpeg.h"
MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
MODULE_DESCRIPTION("Pixart PAC7311");
@@ -39,10 +40,17 @@ struct sd {
unsigned char contrast;
unsigned char colors;
unsigned char autogain;
+ __u8 hflip;
+ __u8 vflip;
+ __u8 qindex;
- char ffseq;
+ char tosof; /* number of bytes before next start of frame */
signed char ag_cnt;
#define AG_CNT_START 13
+
+ __u8 sensor;
+#define SENSOR_PAC7302 0
+#define SENSOR_PAC7311 1
};
/* V4L2 controls supported by the driver */
@@ -54,6 +62,10 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
{
@@ -77,9 +89,10 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
- .maximum = 255,
+#define CONTRAST_MAX 255
+ .maximum = CONTRAST_MAX,
.step = 1,
-#define CONTRAST_DEF 127
+#define CONTRAST_DEF 60
.default_value = CONTRAST_DEF,
},
.set = sd_setcontrast,
@@ -89,9 +102,10 @@ static struct ctrl sd_ctrls[] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Color",
+ .name = "Saturation",
.minimum = 0,
- .maximum = 255,
+#define COLOR_MAX 255
+ .maximum = COLOR_MAX,
.step = 1,
#define COLOR_DEF 127
.default_value = COLOR_DEF,
@@ -113,101 +127,208 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setautogain,
.get = sd_getautogain,
},
+/* next controls work with pac7302 only */
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define HFLIP_DEF 0
+ .default_value = HFLIP_DEF,
+ },
+ .set = sd_sethflip,
+ .get = sd_gethflip,
+ },
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vflip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define VFLIP_DEF 0
+ .default_value = VFLIP_DEF,
+ },
+ .set = sd_setvflip,
+ .get = sd_getvflip,
+ },
};
static struct v4l2_pix_format vga_mode[] = {
- {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
- {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 1},
- {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
};
-#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
-
-static const __u8 pac7311_jpeg_header[] = {
- 0xff, 0xd8,
- 0xff, 0xe0, 0x00, 0x03, 0x20,
- 0xff, 0xc0, 0x00, 0x11, 0x08,
- 0x01, 0xe0, /* 12: height */
- 0x02, 0x80, /* 14: width */
- 0x03, /* 16 */
- 0x01, 0x21, 0x00,
- 0x02, 0x11, 0x01,
- 0x03, 0x11, 0x01,
- 0xff, 0xdb, 0x00, 0x84,
- 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
- 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
- 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
- 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
- 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
- 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
- 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
- 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
- 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
- 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
- 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
- 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
- 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
- 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
- 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
- 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
- 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
- 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
- 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
- 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
- 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
- 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
- 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
- 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
- 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
- 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
- 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
- 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
- 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
- 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
- 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
- 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
- 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
- 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
- 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
- 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
- 0x11, 0x00, 0x3f, 0x00
+/* pac 7302 */
+static const __u8 probe_7302[] = {
+/* index,value */
+ 0xff, 0x01, /* page 1 */
+ 0x78, 0x00, /* deactivate */
+ 0xff, 0x01,
+ 0x78, 0x40, /* led off */
+};
+static const __u8 start_7302[] = {
+/* index, len, [value]* */
+ 0xff, 1, 0x00, /* page 0 */
+ 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
+ 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
+ 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
+ 0x26, 2, 0xaa, 0xaa,
+ 0x2e, 1, 0x31,
+ 0x38, 1, 0x01,
+ 0x3a, 3, 0x14, 0xff, 0x5a,
+ 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
+ 0x00, 0x54, 0x11,
+ 0x55, 1, 0x00,
+ 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
+ 0x6b, 1, 0x00,
+ 0x6e, 3, 0x08, 0x06, 0x00,
+ 0x72, 3, 0x00, 0xff, 0x00,
+ 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
+ 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
+ 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
+ 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
+ 0xd2, 0xeb,
+ 0xaf, 1, 0x02,
+ 0xb5, 2, 0x08, 0x08,
+ 0xb8, 2, 0x08, 0x88,
+ 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
+ 0xcc, 1, 0x00,
+ 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
+ 0xc1, 0xd7, 0xec,
+ 0xdc, 1, 0x01,
+ 0xff, 1, 0x01, /* page 1 */
+ 0x12, 3, 0x02, 0x00, 0x01,
+ 0x3e, 2, 0x00, 0x00,
+ 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
+ 0x7c, 1, 0x00,
+ 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
+ 0x02, 0x00,
+ 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
+ 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+ 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
+ 0xd8, 1, 0x01,
+ 0xdb, 2, 0x00, 0x01,
+ 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
+ 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
+ 0xeb, 1, 0x00,
+ 0xff, 1, 0x02, /* page 2 */
+ 0x22, 1, 0x00,
+ 0xff, 1, 0x03, /* page 3 */
+ 0x00, 255, /* load the page 3 */
+ 0x11, 1, 0x01,
+ 0xff, 1, 0x02, /* page 2 */
+ 0x13, 1, 0x00,
+ 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
+ 0x27, 2, 0x14, 0x0c,
+ 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
+ 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
+ 0x6e, 1, 0x08,
+ 0xff, 1, 0x03, /* page 1 */
+ 0x78, 1, 0x00,
+ 0, 0 /* end of sequence */
+};
+
+/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page3_7302[] = {
+ 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
+ 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
+ 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
+ 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
+ 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
+ 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+ 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
+ 0x00
+};
+
+/* pac 7311 */
+static const __u8 probe_7311[] = {
+ 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
+ 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
+ 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */
+ 0xff, 0x04,
+ 0x27, 0x80,
+ 0x28, 0xca,
+ 0x29, 0x53,
+ 0x2a, 0x0e,
+ 0xff, 0x01,
+ 0x3e, 0x20,
+};
+
+static const __u8 start_7311[] = {
+/* index, len, [value]* */
+ 0xff, 1, 0x01, /* page 1 */
+ 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
+ 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
+ 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
+ 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
+ 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
+ 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
+ 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
+ 0xd0, 0xff,
+ 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
+ 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
+ 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
+ 0x18, 0x20,
+ 0x96, 3, 0x01, 0x08, 0x04,
+ 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
+ 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
+ 0x3f, 0x00, 0x0a, 0x01, 0x00,
+ 0xff, 1, 0x04, /* page 4 */
+ 0x00, 254, /* load the page 4 */
+ 0x11, 1, 0x01,
+ 0, 0 /* end of sequence */
+};
+
+/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page4_7311[] = {
+ 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
+ 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
+ 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
+ 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
+ 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
};
static void reg_w_buf(struct gspca_dev *gspca_dev,
- __u16 index,
- const char *buffer, __u16 len)
+ __u8 index,
+ const char *buffer, int len)
{
memcpy(gspca_dev->usb_buf, buffer, len);
usb_control_msg(gspca_dev->dev,
@@ -220,7 +341,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
}
static __u8 reg_r(struct gspca_dev *gspca_dev,
- __u16 index)
+ __u8 index)
{
usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
@@ -233,7 +354,7 @@ static __u8 reg_r(struct gspca_dev *gspca_dev,
}
static void reg_w(struct gspca_dev *gspca_dev,
- __u16 index,
+ __u8 index,
__u8 value)
{
gspca_dev->usb_buf[0] = value;
@@ -245,6 +366,74 @@ static void reg_w(struct gspca_dev *gspca_dev,
500);
}
+static void reg_w_seq(struct gspca_dev *gspca_dev,
+ const __u8 *seq, int len)
+{
+ while (--len >= 0) {
+ reg_w(gspca_dev, seq[0], seq[1]);
+ seq += 2;
+ }
+}
+
+/* load the beginning of a page */
+static void reg_w_page(struct gspca_dev *gspca_dev,
+ const __u8 *page, int len)
+{
+ int index;
+
+ for (index = 0; index < len; index++) {
+ if (page[index] == 0xaa) /* skip this index */
+ continue;
+ gspca_dev->usb_buf[0] = page[index];
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, gspca_dev->usb_buf, 1,
+ 500);
+ }
+}
+
+/* output a variable sequence */
+static void reg_w_var(struct gspca_dev *gspca_dev,
+ const __u8 *seq)
+{
+ int index, len;
+
+ for (;;) {
+ index = *seq++;
+ len = *seq++;
+ switch (len) {
+ case 0:
+ return;
+ case 254:
+ reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
+ break;
+ case 255:
+ reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
+ break;
+ default:
+ if (len > 32) {
+ PDEBUG(D_ERR|D_STREAM,
+ "Incorrect variable sequence");
+ return;
+ }
+ while (len > 0) {
+ if (len < 8) {
+ reg_w_buf(gspca_dev, index, seq, len);
+ seq += len;
+ break;
+ }
+ reg_w_buf(gspca_dev, index, seq, 8);
+ seq += 8;
+ index += 8;
+ len -= 8;
+ }
+ }
+ }
+ /* not reached */
+}
+
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@@ -252,40 +441,75 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
- PDEBUG(D_CONF, "Find Sensor PAC7311");
- reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x27, 0x80);
- reg_w(gspca_dev, 0x28, 0xca);
- reg_w(gspca_dev, 0x29, 0x53);
- reg_w(gspca_dev, 0x2a, 0x0e);
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x3e, 0x20);
-
cam = &gspca_dev->cam;
cam->epaddr = 0x05;
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ sd->sensor = id->driver_info;
+ if (sd->sensor == SENSOR_PAC7302) {
+ PDEBUG(D_CONF, "Find Sensor PAC7302");
+ reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
+
+ cam->cam_mode = &vga_mode[2]; /* only 640x480 */
+ cam->nmodes = 1;
+ } else {
+ PDEBUG(D_CONF, "Find Sensor PAC7311");
+ reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
+
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ }
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->autogain = AUTOGAIN_DEF;
+ sd->hflip = HFLIP_DEF;
+ sd->vflip = VFLIP_DEF;
+ sd->qindex = 3;
sd->ag_cnt = -1;
return 0;
}
+/* rev 12a only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, v;
+ static const __u8 max[10] =
+ {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
+ 0xd4, 0xec};
+ static const __u8 delta[10] =
+ {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
+ 0x11, 0x0b};
+
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ for (i = 0; i < 10; i++) {
+ v = max[i];
+ v += (sd->brightness - BRIGHTNESS_MAX)
+ * 150 / BRIGHTNESS_MAX; /* 200 ? */
+ v -= delta[i] * sd->contrast / CONTRAST_MAX;
+ if (v < 0)
+ v = 0;
+ else if (v > 0xff)
+ v = 0xff;
+ reg_w(gspca_dev, 0xa2 + i, v);
+ }
+ reg_w(gspca_dev, 0xdc, 0x01);
+}
+
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int brightness;
+ if (sd->sensor == SENSOR_PAC7302) {
+ setbrightcont(gspca_dev);
+ return;
+ }
/*jfm: inverted?*/
brightness = BRIGHTNESS_MAX - sd->brightness;
reg_w(gspca_dev, 0xff, 0x04);
-/* reg_w(gspca_dev, 0x0e, 0x00); */
+ reg_w(gspca_dev, 0x0e, 0x00);
reg_w(gspca_dev, 0x0f, brightness);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
@@ -296,19 +520,41 @@ static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->sensor == SENSOR_PAC7302) {
+ setbrightcont(gspca_dev);
+ return;
+ }
reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x80, sd->contrast);
+ reg_w(gspca_dev, 0x10, sd->contrast);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
- PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
}
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->sensor == SENSOR_PAC7302) {
+ int i, v;
+ static const int a[9] =
+ {217, -212, 0, -101, 170, -67, -38, -315, 355};
+ static const int b[9] =
+ {19, 106, 0, 19, 106, 1, 19, 106, 1};
+
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ reg_w(gspca_dev, 0x11, 0x01);
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ for (i = 0; i < 9; i++) {
+ v = a[i] * sd->colors / COLOR_MAX + b[i];
+ reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+ reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+ }
+ reg_w(gspca_dev, 0xdc, 0x01);
+ return;
+ }
reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x10, sd->colors);
+ reg_w(gspca_dev, 0x80, sd->colors);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
@@ -326,84 +572,37 @@ static void setautogain(struct gspca_dev *gspca_dev)
}
}
+/* this function is used by pac7302 only */
+static void sethvflip(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data;
+
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ data = (sd->hflip ? 0x00 : 0x08)
+ | (sd->vflip ? 0x04 : 0x00);
+ reg_w(gspca_dev, 0x21, data);
+ reg_w(gspca_dev, 0x11, 0x01);
+}
+
/* this function is called at open time */
static int sd_open(struct gspca_dev *gspca_dev)
{
- reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Turn on LED */
return 0;
}
static void sd_start(struct gspca_dev *gspca_dev)
{
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
- reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
- reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
- reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
- reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
- reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
- reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
- reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
- reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
- reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
- reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
- reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
- reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
- reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
- reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
- reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
- reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
- reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
- reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
- reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->tosof = 0;
+
+ if (sd->sensor == SENSOR_PAC7302)
+ reg_w_var(gspca_dev, start_7302);
+ else
+ reg_w_var(gspca_dev, start_7311);
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x02, 0x04);
- reg_w(gspca_dev, 0x03, 0x54);
- reg_w(gspca_dev, 0x04, 0x07);
- reg_w(gspca_dev, 0x05, 0x2b);
- reg_w(gspca_dev, 0x06, 0x09);
- reg_w(gspca_dev, 0x07, 0x0f);
- reg_w(gspca_dev, 0x08, 0x09);
- reg_w(gspca_dev, 0x09, 0x00);
- reg_w(gspca_dev, 0x0c, 0x07);
- reg_w(gspca_dev, 0x0d, 0x00);
- reg_w(gspca_dev, 0x0e, 0x00);
- reg_w(gspca_dev, 0x0f, 0x62);
- reg_w(gspca_dev, 0x10, 0x08);
- reg_w(gspca_dev, 0x12, 0x07);
- reg_w(gspca_dev, 0x13, 0x00);
- reg_w(gspca_dev, 0x14, 0x00);
- reg_w(gspca_dev, 0x15, 0x00);
- reg_w(gspca_dev, 0x16, 0x00);
- reg_w(gspca_dev, 0x17, 0x00);
- reg_w(gspca_dev, 0x18, 0x00);
- reg_w(gspca_dev, 0x19, 0x00);
- reg_w(gspca_dev, 0x1a, 0x00);
- reg_w(gspca_dev, 0x1b, 0x03);
- reg_w(gspca_dev, 0x1c, 0xa0);
- reg_w(gspca_dev, 0x1d, 0x01);
- reg_w(gspca_dev, 0x1e, 0xf4);
- reg_w(gspca_dev, 0x21, 0x00);
- reg_w(gspca_dev, 0x22, 0x08);
- reg_w(gspca_dev, 0x24, 0x03);
- reg_w(gspca_dev, 0x26, 0x00);
- reg_w(gspca_dev, 0x27, 0x01);
- reg_w(gspca_dev, 0x28, 0xca);
- reg_w(gspca_dev, 0x29, 0x10);
- reg_w(gspca_dev, 0x2a, 0x06);
- reg_w(gspca_dev, 0x2b, 0x78);
- reg_w(gspca_dev, 0x2c, 0x00);
- reg_w(gspca_dev, 0x2d, 0x00);
- reg_w(gspca_dev, 0x2e, 0x00);
- reg_w(gspca_dev, 0x2f, 0x00);
- reg_w(gspca_dev, 0x30, 0x23);
- reg_w(gspca_dev, 0x31, 0x28);
- reg_w(gspca_dev, 0x32, 0x04);
- reg_w(gspca_dev, 0x33, 0x11);
- reg_w(gspca_dev, 0x34, 0x00);
- reg_w(gspca_dev, 0x35, 0x00);
- reg_w(gspca_dev, 0x11, 0x01);
setcontrast(gspca_dev);
setbrightness(gspca_dev);
setcolors(gspca_dev);
@@ -411,44 +610,57 @@ static void sd_start(struct gspca_dev *gspca_dev)
/* set correct resolution */
switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
- case 2: /* 160x120 */
+ case 2: /* 160x120 pac7311 */
reg_w(gspca_dev, 0xff, 0x04);
reg_w(gspca_dev, 0x02, 0x03);
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x08, 0x09);
reg_w(gspca_dev, 0x17, 0x20);
reg_w(gspca_dev, 0x1b, 0x00);
-/* reg_w(gspca_dev, 0x80, 0x69); */
reg_w(gspca_dev, 0x87, 0x10);
break;
- case 1: /* 320x240 */
+ case 1: /* 320x240 pac7311 */
reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x02, 0x03);
+ reg_w(gspca_dev, 0x02, 0x07);
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x08, 0x09);
reg_w(gspca_dev, 0x17, 0x30);
-/* reg_w(gspca_dev, 0x80, 0x3f); */
reg_w(gspca_dev, 0x87, 0x11);
break;
case 0: /* 640x480 */
+ if (sd->sensor == SENSOR_PAC7302)
+ break;
reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x02, 0x03);
+ reg_w(gspca_dev, 0x02, 0x07);
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x08, 0x08);
reg_w(gspca_dev, 0x17, 0x00);
-/* reg_w(gspca_dev, 0x80, 0x1c); */
reg_w(gspca_dev, 0x87, 0x12);
break;
}
/* start stream */
reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x78, 0x04);
- reg_w(gspca_dev, 0x78, 0x05);
+ if (sd->sensor == SENSOR_PAC7302) {
+ sethvflip(gspca_dev);
+ reg_w(gspca_dev, 0x78, 0x01);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x01);
+ } else {
+ reg_w(gspca_dev, 0x78, 0x44);
+ reg_w(gspca_dev, 0x78, 0x45);
+ }
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w(gspca_dev, 0x78, 0x00);
+ reg_w(gspca_dev, 0x78, 0x00);
+ return;
+ }
reg_w(gspca_dev, 0xff, 0x04);
reg_w(gspca_dev, 0x27, 0x80);
reg_w(gspca_dev, 0x28, 0xca);
@@ -456,28 +668,24 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x2a, 0x0e);
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x3e, 0x20);
- reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
}
static void sd_stop0(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x40);
+ }
}
/* this function is called at close time */
static void sd_close(struct gspca_dev *gspca_dev)
{
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x27, 0x80);
- reg_w(gspca_dev, 0x28, 0xca);
- reg_w(gspca_dev, 0x29, 0x53);
- reg_w(gspca_dev, 0x2a, 0x0e);
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x3e, 0x20);
- reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
}
static void do_autogain(struct gspca_dev *gspca_dev)
@@ -504,144 +712,120 @@ static void do_autogain(struct gspca_dev *gspca_dev)
else if (Gbright < 4)
Gbright = 4;
PDEBUG(D_FRAM, "gbright %d", Gbright);
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x0f, Gbright);
- /* load registers to sensor (Bit 0, auto clear) */
- reg_w(gspca_dev, 0x11, 0x01);
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w(gspca_dev, 0xff, 0x03);
+ reg_w(gspca_dev, 0x10, Gbright);
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+ } else {
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x0f, Gbright);
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+ }
}
}
+/* this function is run at interrupt level */
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- unsigned char tmpbuf[4];
- int i, p, ffseq;
-
-/* if (len < 5) { */
- if (len < 6) {
-/* gspca_dev->last_packet_type = DISCARD_PACKET; */
- return;
- }
-
- ffseq = sd->ffseq;
-
- for (p = 0; p < len - 6; p++) {
- if ((data[0 + p] == 0xff)
- && (data[1 + p] == 0xff)
- && (data[2 + p] == 0x00)
- && (data[3 + p] == 0xff)
- && (data[4 + p] == 0x96)) {
-
- /* start of frame */
- if (sd->ag_cnt >= 0 && p > 28) {
- sd->lum_sum += data[p - 23];
- if (--sd->ag_cnt < 0) {
- sd->ag_cnt = AG_CNT_START;
- atomic_set(&sd->avg_lum,
- sd->lum_sum / AG_CNT_START);
- sd->lum_sum = 0;
- atomic_set(&sd->do_gain, 1);
- }
+ int i;
+
+#define INTER_FRAME 0x53 /* eof + inter frame + sof */
+#define LUM_OFFSET 0x1e /* reverse offset / start of frame */
+
+#if 0 /*fixme:test+*/
+/* dump the packet */
+ if (gspca_debug & 0x200) {
+ static char tmp[50];
+
+ PDEBUG(0x200, "pkt_scan");
+ tmp[0] = 0;
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0 && i != 0) {
+ PDEBUG(0x200, "%s", tmp);
+ tmp[0] = 0;
}
-
- /* copy the end of data to the current frame */
- frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
- data, p);
-
- /* put the JPEG header in the new frame */
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
- (unsigned char *) pac7311_jpeg_header,
- 12);
- tmpbuf[0] = gspca_dev->height >> 8;
- tmpbuf[1] = gspca_dev->height & 0xff;
- tmpbuf[2] = gspca_dev->width >> 8;
- tmpbuf[3] = gspca_dev->width & 0xff;
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- tmpbuf, 4);
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- (unsigned char *) &pac7311_jpeg_header[16],
- PAC7311_JPEG_HEADER_SIZE - 16);
-
- data += p + 7;
- len -= p + 7;
- ffseq = 0;
- break;
+ sprintf(&tmp[(i % 16) * 3], "%02x ", data[i]);
}
+ if (tmp[0] != 0)
+ PDEBUG(0x200, "%s", tmp);
}
-
- /* remove the 'ff ff ff xx' sequences */
- switch (ffseq) {
- case 3:
- data += 1;
- len -= 1;
- break;
- case 2:
- if (data[0] == 0xff) {
- data += 2;
- len -= 2;
- frame->data_end -= 2;
- }
- break;
- case 1:
- if (data[0] == 0xff
- && data[1] == 0xff) {
- data += 3;
- len -= 3;
- frame->data_end -= 1;
- }
- break;
+#endif /*fixme:test-*/
+ /*
+ * inside a frame, there may be:
+ * escaped ff ('ff 00')
+ * sequences'ff ff ff xx' to remove
+ * end of frame ('ff d9')
+ * at the end of frame, there are:
+ * ff d9 end of frame
+ * 0x33 bytes
+ * one byte luminosity
+ * 0x16 bytes
+ * ff ff 00 ff 96 62 44 start of frame
+ */
+
+ if (sd->tosof != 0) { /* if outside a frame */
+
+ /* get the luminosity and go to the start of frame */
+ data += sd->tosof;
+ len -= sd->tosof;
+ if (sd->tosof > LUM_OFFSET)
+ sd->lum_sum += data[-LUM_OFFSET];
+ sd->tosof = 0;
+ jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
}
- for (i = 0; i < len - 4; i++) {
- if (data[i] == 0xff
- && data[i + 1] == 0xff
- && data[i + 2] == 0xff) {
- memmove(&data[i], &data[i + 4], len - i - 4);
- len -= 4;
+
+ for (i = 0; i < len; i++) {
+ if (data[i] != 0xff)
+ continue;
+ switch (data[i + 1]) {
+ case 0xd9: /* 'ff d9' end of frame */
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame, data, i + 2);
+ data += i + INTER_FRAME;
+ len -= i + INTER_FRAME;
+ i = 0;
+ if (len > -LUM_OFFSET)
+ sd->lum_sum += data[-LUM_OFFSET];
+ if (len < 0) {
+ sd->tosof = -len;
+ break;
+ }
+ jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
+ break;
+#if 0 /*fixme:test+*/
+/* is there a start of frame ? */
+ case 0xff: /* 'ff ff' */
+ if (data[i + 2] == 0x00) {
+ static __u8 ffd9[2] = {0xff, 0xd9};
+
+ gspca_frame_add(gspca_dev,
+ INTER_PACKET,
+ frame, data,
+ i + 7 - INTER_FRAME);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame, ffd9, 2);
+ data += i + 7;
+ len -= i + 7;
+ i = 0;
+ jpeg_put_header(gspca_dev, frame,
+ sd->qindex, 0x21);
+ break;
+ }
+ break;
+#endif /*fixme:test-*/
}
}
- ffseq = 0;
- if (data[len - 4] == 0xff) {
- if (data[len - 3] == 0xff
- && data[len - 2] == 0xff) {
- len -= 4;
- }
- } else if (data[len - 3] == 0xff) {
- if (data[len - 2] == 0xff
- && data[len - 1] == 0xff)
- ffseq = 3;
- } else if (data[len - 2] == 0xff) {
- if (data[len - 1] == 0xff)
- ffseq = 2;
- } else if (data[len - 1] == 0xff)
- ffseq = 1;
- sd->ffseq = ffseq;
- gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-/* sd->brightness = reg_r(gspca_dev, 0x08);
- return sd->brightness; */
-/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
-}
-
-#if 0
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-/* sd->contrast = reg_r(gspca_dev, 0x0e);
- return sd->contrast; */
- PDEBUG(D_CONF, "getcontrast: Not implemented yet");
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ frame, data, i);
}
-#endif
-
-#if 0
-static void getcolors(struct gspca_dev *gspca_dev)
-{
-}
-#endif
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
@@ -657,7 +841,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- getbrightness(gspca_dev);
*val = sd->brightness;
return 0;
}
@@ -676,7 +859,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
-/* getcontrast(gspca_dev); */
*val = sd->contrast;
return 0;
}
@@ -695,7 +877,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
-/* getcolors(gspca_dev); */
*val = sd->colors;
return 0;
}
@@ -718,6 +899,42 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hflip = val;
+ if (gspca_dev->streaming)
+ sethvflip(gspca_dev);
+ return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hflip;
+ return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->vflip = val;
+ if (gspca_dev->streaming)
+ sethvflip(gspca_dev);
+ return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->vflip;
+ return 0;
+}
+
/* sub-driver description */
static struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -735,13 +952,13 @@ static struct sd_desc sd_desc = {
/* -- module initialisation -- */
static __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x093a, 0x2600)},
- {USB_DEVICE(0x093a, 0x2601)},
- {USB_DEVICE(0x093a, 0x2603)},
- {USB_DEVICE(0x093a, 0x2608)},
- {USB_DEVICE(0x093a, 0x260e)},
- {USB_DEVICE(0x093a, 0x260f)},
- {USB_DEVICE(0x093a, 0x2621)},
+ {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -759,6 +976,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c
index 4d979fa39..afbb969ba 100644
--- a/linux/drivers/media/video/gspca/sonixb.c
+++ b/linux/drivers/media/video/gspca/sonixb.c
@@ -1264,6 +1264,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index b30f7eeda..217a31a0e 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -54,8 +54,10 @@ struct sd {
#define SENSOR_HV7131R 0
#define SENSOR_MI0360 1
#define SENSOR_MO4000 2
-#define SENSOR_OV7648 3
-#define SENSOR_OV7660 4
+#define SENSOR_OM6802 3
+#define SENSOR_OV7630 4
+#define SENSOR_OV7648 5
+#define SENSOR_OV7660 6
unsigned char i2c_base;
};
@@ -76,7 +78,8 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
- .maximum = 0xffff,
+#define BRIGHTNESS_MAX 0xffff
+ .maximum = BRIGHTNESS_MAX,
.step = 1,
#define BRIGHTNESS_DEF 0x7fff
.default_value = BRIGHTNESS_DEF,
@@ -90,7 +93,8 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
- .maximum = 127,
+#define CONTRAST_MAX 127
+ .maximum = CONTRAST_MAX,
.step = 1,
#define CONTRAST_DEF 63
.default_value = CONTRAST_DEF,
@@ -104,9 +108,9 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Color",
.minimum = 0,
- .maximum = 255,
+ .maximum = 64,
.step = 1,
-#define COLOR_DEF 127
+#define COLOR_DEF 32
.default_value = COLOR_DEF,
},
.set = sd_setcolors,
@@ -131,7 +135,7 @@ static struct ctrl sd_ctrls[] = {
static struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
- .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -180,6 +184,31 @@ static const __u8 sn_mo4000[] = {
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+static const __u8 sn_om6802[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x23, 0x72, 0x00, 0x1a, 0x34, 0x27, 0x20,
+/* reg8 reg9 rega regb regc regd rege regf */
+ 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40,
+/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x22, 0x44, 0x63, 0x7d, 0x92, 0xa3, 0xaf,
+ 0xbc, 0xc4, 0xcd, 0xd5, 0xdc, 0xe1, 0xe8, 0xef,
+ 0xf7
+};
+
+static const __u8 sn_ov7630[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x21, 0x40, 0x00, 0x1a, 0x20, 0x1f, 0x20,
+/* reg8 reg9 rega regb regc regd rege regf */
+ 0xa1, 0x21, 0x76, 0x21, 0x00, 0x00, 0x00, 0x10,
+/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2,
+/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
static const __u8 sn_ov7648[] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20,
@@ -219,31 +248,26 @@ static const __u8 *sn_tb[] = {
sn_hv7131,
sn_mi0360,
sn_mo4000,
+ sn_om6802,
+ sn_ov7630,
sn_ov7648,
sn_ov7660
};
-static const __u8 regsn20[] = {
+static const __u8 gamma_def[] = {
0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
};
-static const __u8 regsn20_sn9c325[] = {
- 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
- 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
-};
static const __u8 reg84[] = {
0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
-/* 0x00, 0x00, 0x00, 0x00, 0x00 */
+#if 1
+ 0xf7, 0x0f, 0x00, 0x00, 0x00
+#else
0xf7, 0x0f, 0x0a, 0x00, 0x00
+#endif
};
-static const __u8 reg84_sn9c325[] = {
- 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
- 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
- 0xf8, 0x0f, 0x00, 0x00, 0x00
-};
-
static const __u8 hv7131r_sensor_init[][8] = {
{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
{0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
@@ -352,6 +376,92 @@ static const __u8 mo4000_sensor_init[][8] = {
{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
{}
};
+static __u8 om6802_sensor_init[][8] = {
+ {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10},
+/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */
+ {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10},
+ /* white balance & auto-exposure */
+/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10},
+ * set color mode */
+/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10},
+ * max AGC value in AE */
+/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * preset AGC */
+/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * preset brightness */
+/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * preset contrast */
+/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10},
+ * preset gamma */
+ {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10},
+ /* luminance mode (0x4f = AE) */
+ {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10},
+ /* preset shutter */
+/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * auto frame rate */
+/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */
+
+/* {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */
+/* {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */
+/* {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */
+/* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
+ {}
+};
+static const __u8 ov7630_sensor_init[][8] = {
+ {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/* win: i2c_r from 00 to 80 */
+ {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
+ {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10},
+ {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+ {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10},
+ {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10},
+ {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10},
+ {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10},
+ {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10},
+ {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10},
+ {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10},
+ {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10},
+ {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10},
+ {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10},
+ {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10},
+ {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+ {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+/* */
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/*fixme: + 0x12, 0x04*/
+ {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
+/* */
+ {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10},
+/* */
+ {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10},
+ {}
+};
static const __u8 ov7660_sensor_init[][8] = {
{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
/* (delay 20ms) */
@@ -677,7 +787,11 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
static const __u8 regd4[] = {0x60, 0x00, 0x00};
reg_w1(gspca_dev, 0xf1, 0x00);
- reg_w1(gspca_dev, 0x01, 0x00); /*jfm was sn9c1xx[1] in v1*/
+#if 1
+ reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
+#else
+ reg_w1(gspca_dev, 0x01, 0x00); /*jfm: in some win traces*/
+#endif
/* configure gpio */
reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
@@ -697,29 +811,44 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
- switch (sd->bridge) {
-#if 0
+ switch (sd->sensor) {
+ case SENSOR_OM6802:
+ reg_w1(gspca_dev, 0x02, 0x71);
+ reg_w1(gspca_dev, 0x01, 0x42);
+ reg_w1(gspca_dev, 0x17, 0x64);
+ reg_w1(gspca_dev, 0x01, 0x42);
+ break;
+#if 1
/*jfm: from win trace */
- case BRIDGE_SN9C120:
+ case SENSOR_OV7630:
reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x20);
+ reg_w1(gspca_dev, 0x17, 0xe2);
reg_w1(gspca_dev, 0x01, 0x60);
+ reg_w1(gspca_dev, 0x01, 0x40);
break;
#endif
- case BRIDGE_SN9C325:
+ case SENSOR_OV7648:
reg_w1(gspca_dev, 0x01, 0x43);
reg_w1(gspca_dev, 0x17, 0xae);
reg_w1(gspca_dev, 0x01, 0x42);
break;
+#if 0
+/*jfm: from win trace */
+ case SENSOR_OV7660:
+ reg_w1(gspca_dev, 0x01, 0x61);
+ reg_w1(gspca_dev, 0x17, 0x20);
+ reg_w1(gspca_dev, 0x01, 0x60);
+ break;
+#endif
default:
reg_w1(gspca_dev, 0x01, 0x43);
reg_w1(gspca_dev, 0x17, 0x61);
reg_w1(gspca_dev, 0x01, 0x42);
- }
-
- if (sd->sensor == SENSOR_HV7131R) {
- if (probesensor(gspca_dev) < 0)
- return -ENODEV;
+ if (sd->sensor == SENSOR_HV7131R) {
+ if (probesensor(gspca_dev) < 0)
+ return -ENODEV;
+ }
+ break;
}
return 0;
}
@@ -757,6 +886,40 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
}
}
+static void om6802_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ while (om6802_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, om6802_sensor_init[i]);
+ i++;
+ }
+}
+
+static void ov7630_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 76 01 */
+ i++;
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 (RGB+SRST) */
+ i++;
+ msleep(20);
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */
+ i++;
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 */
+ i++;
+ msleep(20);
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */
+ i++;
+/*jfm:win i2c_r from 00 to 80*/
+
+ while (ov7630_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]);
+ i++;
+ }
+}
+
static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
{
int i = 0;
@@ -916,16 +1079,53 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
| ((expoMo10[3] & 0x30) >> 4));
break;
}
+ case SENSOR_OM6802: {
+ __u8 gainOm[] =
+ { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
+
+ if (expo > 0x03ff)
+ expo = 0x03ff;
+ if (expo < 0x0001)
+ expo = 0x0001;
+ gainOm[3] = expo >> 2;
+ i2c_w8(gspca_dev, gainOm);
+ reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
+ PDEBUG(D_CONF, "set exposure %d", gainOm[3]);
+ break;
+ }
}
return expo;
}
+/* this function is used for sensors o76xx only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned val;
+ __u8 reg84_full[13];
+
+ memset(reg84_full, 0, sizeof reg84_full);
+ val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10; /* 10..30 */
+ reg84_full[2] = val;
+ reg84_full[0] = (val + 1) / 2;
+ reg84_full[4] = (val + 1) / 5;
+ if (val > BRIGHTNESS_DEF)
+ val = (sd->brightness - BRIGHTNESS_DEF) * 0x20
+ / BRIGHTNESS_MAX;
+ else
+ val = 0;
+ reg84_full[10] = val; /* 00..1f */
+ reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
+}
+
+/* sensor != ov76xx */
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
unsigned int expo;
__u8 k2;
+ k2 = sd->brightness >> 10;
switch (sd->sensor) {
case SENSOR_HV7131R:
expo = sd->brightness << 4;
@@ -940,12 +1140,17 @@ static void setbrightness(struct gspca_dev *gspca_dev)
expo = sd->brightness >> 4;
sd->exposure = setexposure(gspca_dev, expo);
break;
+ case SENSOR_OM6802:
+ expo = sd->brightness >> 6;
+ sd->exposure = setexposure(gspca_dev, expo);
+ k2 = sd->brightness >> 11;
+ break;
}
- k2 = sd->brightness >> 10;
reg_w1(gspca_dev, 0x96, k2);
}
+/* sensor != ov76xx */
static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -962,15 +1167,18 @@ static void setcontrast(struct gspca_dev *gspca_dev)
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 data;
- int colour;
+ __u8 blue, red;
- colour = sd->colors - 128;
- if (colour > 0)
- data = (colour + 32) & 0x7f; /* blue */
- else
- data = (-colour + 32) & 0x7f; /* red */
- reg_w1(gspca_dev, 0x05, data);
+ if (sd->colors >= 32) {
+ red = 32 + (sd->colors - 32) / 2;
+ blue = 64 - sd->colors;
+ } else {
+ red = sd->colors;
+ blue = 32 + (32 - sd->colors) / 2;
+ }
+ reg_w1(gspca_dev, 0x05, red);
+/* reg_w1(gspca_dev, 0x07, 32); */
+ reg_w1(gspca_dev, 0x06, blue);
}
static void setautogain(struct gspca_dev *gspca_dev)
@@ -1000,8 +1208,8 @@ static void sd_start(struct gspca_dev *gspca_dev)
static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
- static const __u8 CE_sn9c325[] =
- { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */
+ static const __u8 CE_ov76xx[] =
+ { 0x32, 0xdd, 0x32, 0xdd }; /* OV7630/48 */
sn9c1xx = sn_tb[(int) sd->sensor];
configure_gpio(gspca_dev, sn9c1xx);
@@ -1019,13 +1227,16 @@ static void sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0xc8, 0x50);
reg_w1(gspca_dev, 0xc9, 0x3c);
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ reg17 = 0xe2;
+ break;
+ case SENSOR_OV7648:
reg17 = 0xae;
break;
-#if 0
+#if 1
/*jfm: from win trace */
- case BRIDGE_SN9C120:
+ case SENSOR_OV7660:
reg17 = 0xa0;
break;
#endif
@@ -1038,24 +1249,23 @@ static void sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
+ reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
+ for (i = 0; i < 8; i++)
+ reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+#if 0
switch (sd->bridge) {
case BRIDGE_SN9C325:
- reg_w(gspca_dev, 0x20, regsn20_sn9c325,
- sizeof regsn20_sn9c325);
- for (i = 0; i < 8; i++)
- reg_w(gspca_dev, 0x84, reg84_sn9c325,
- sizeof reg84_sn9c325);
reg_w1(gspca_dev, 0x9a, 0x0a);
reg_w1(gspca_dev, 0x99, 0x60);
break;
default:
- reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
- for (i = 0; i < 8; i++)
- reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+#endif
reg_w1(gspca_dev, 0x9a, 0x08);
reg_w1(gspca_dev, 0x99, 0x59);
+#if 0
break;
}
+#endif
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
if (mode)
@@ -1080,6 +1290,15 @@ static void sd_start(struct gspca_dev *gspca_dev)
/* reg1 = 0x06; * 640 clk 24Mz (done) */
}
break;
+ case SENSOR_OM6802:
+ om6802_InitSensor(gspca_dev);
+ reg17 = 0x64; /* 640 MCKSIZE */
+ break;
+ case SENSOR_OV7630:
+ ov7630_InitSensor(gspca_dev);
+ reg17 = 0xe2;
+ reg1 = 0x44;
+ break;
case SENSOR_OV7648:
ov7648_InitSensor(gspca_dev);
reg17 = 0xa2;
@@ -1110,9 +1329,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
}
reg_w(gspca_dev, 0xc0, C0, 6);
reg_w(gspca_dev, 0xca, CA, 4);
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
- reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ case SENSOR_OV7648:
+ reg_w(gspca_dev, 0xce, CE_ov76xx, 4);
break;
default:
reg_w(gspca_dev, 0xce, CE, 4);
@@ -1131,8 +1351,18 @@ static void sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x17, reg17);
reg_w1(gspca_dev, 0x01, reg1);
- setbrightness(gspca_dev);
- setcontrast(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ case SENSOR_MO4000:
+ case SENSOR_OM6802:
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ break;
+ default: /* OV76xx */
+ setbrightcont(gspca_dev);
+ break;
+ }
setautogain(gspca_dev);
}
@@ -1156,6 +1386,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
i2c_w8(gspca_dev, stopmi0360);
data = 0x29;
break;
+ case SENSOR_OV7630:
case SENSOR_OV7648:
data = 0x29;
break;
@@ -1169,7 +1400,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
reg_w1(gspca_dev, 0x01, data);
- reg_w1(gspca_dev, 0xf1, 0x01);
+ reg_w1(gspca_dev, 0xf1, 0x00);
}
static void sd_stop0(struct gspca_dev *gspca_dev)
@@ -1211,6 +1442,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
default:
/* case SENSOR_MO4000: */
/* case SENSOR_MI0360: */
+/* case SENSOR_OM6802: */
expotimes = sd->exposure;
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
@@ -1266,69 +1498,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
-static unsigned int getexposure(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u8 hexpo, mexpo, lexpo;
-
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- /* read sensor exposure */
- i2c_r5(gspca_dev, 0x25);
- return (gspca_dev->usb_buf[0] << 16)
- | (gspca_dev->usb_buf[1] << 8)
- | gspca_dev->usb_buf[2];
- case SENSOR_MI0360:
- /* read sensor exposure */
- i2c_r5(gspca_dev, 0x09);
- return (gspca_dev->usb_buf[0] << 8)
- | gspca_dev->usb_buf[1];
- case SENSOR_MO4000:
- i2c_r5(gspca_dev, 0x0e);
- hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */
- mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */
- lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
- PDEBUG(D_CONF, "exposure %d",
- (hexpo << 10) | (mexpo << 2) | lexpo);
- return (hexpo << 10) | (mexpo << 2) | lexpo;
- default:
-/* case SENSOR_OV7648: * jfm: is it ok for 7648? */
-/* case SENSOR_OV7660: */
- /* read sensor exposure */
- i2c_r5(gspca_dev, 0x04);
- hexpo = gspca_dev->usb_buf[3] & 0x2f;
- lexpo = gspca_dev->usb_buf[0] & 0x02;
- i2c_r5(gspca_dev, 0x08);
- mexpo = gspca_dev->usb_buf[2];
- return (hexpo << 10) | (mexpo << 2) | lexpo;
- }
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- /* hardcoded registers seem not readable */
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- sd->brightness = getexposure(gspca_dev) >> 4;
- break;
- case SENSOR_MI0360:
- sd->brightness = getexposure(gspca_dev) << 4;
- break;
- case SENSOR_MO4000:
- sd->brightness = getexposure(gspca_dev) << 4;
- break;
- }
-}
-
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightness(gspca_dev);
+ if (gspca_dev->streaming) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ case SENSOR_MO4000:
+ case SENSOR_OM6802:
+ setbrightness(gspca_dev);
+ break;
+ default: /* OV76xx */
+ setbrightcont(gspca_dev);
+ break;
+ }
+ }
return 0;
}
@@ -1336,7 +1523,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- getbrightness(gspca_dev);
*val = sd->brightness;
return 0;
}
@@ -1346,8 +1532,19 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
+ if (gspca_dev->streaming) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ case SENSOR_MO4000:
+ case SENSOR_OM6802:
+ setcontrast(gspca_dev);
+ break;
+ default: /* OV76xx */
+ setbrightcont(gspca_dev);
+ break;
+ }
+ }
return 0;
}
@@ -1443,11 +1640,11 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
- {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)},
-/* bw600.inf:
- {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */
+ {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
+/*bw600.inf:*/
+ {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/
{USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
-/* {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */
+ {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)},
/* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
#ifndef CONFIG_USB_SN9C102
{USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
@@ -1475,6 +1672,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c
index be88d30a3..2aff5af9a 100644
--- a/linux/drivers/media/video/gspca/spca500.c
+++ b/linux/drivers/media/video/gspca/spca500.c
@@ -1110,6 +1110,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c
index f8df18e85..df657cb9d 100644
--- a/linux/drivers/media/video/gspca/spca501.c
+++ b/linux/drivers/media/video/gspca/spca501.c
@@ -2165,6 +2165,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c
index 1cde4b34f..440e6853c 100644
--- a/linux/drivers/media/video/gspca/spca505.c
+++ b/linux/drivers/media/video/gspca/spca505.c
@@ -924,6 +924,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c
index f622fa757..ae772488c 100644
--- a/linux/drivers/media/video/gspca/spca506.c
+++ b/linux/drivers/media/video/gspca/spca506.c
@@ -772,6 +772,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c
index 52e2f7462..585468863 100644
--- a/linux/drivers/media/video/gspca/spca508.c
+++ b/linux/drivers/media/video/gspca/spca508.c
@@ -1705,6 +1705,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c
index 1073ac3d2..d686b6bd7 100644
--- a/linux/drivers/media/video/gspca/spca561.c
+++ b/linux/drivers/media/video/gspca/spca561.c
@@ -32,68 +32,47 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned short contrast;
- __u8 brightness;
+ __u16 contrast; /* rev72a only */
+#define CONTRAST_MIN 0x0000
+#define CONTRAST_DEF 0x2000
+#define CONTRAST_MAX 0x3fff
+
+ __u16 exposure; /* rev12a only */
+#define EXPOSURE_MIN 0
+#define EXPOSURE_DEF 200
+#define EXPOSURE_MAX 762
+
+ __u8 brightness; /* rev72a only */
+#define BRIGHTNESS_MIN 0
+#define BRIGHTNESS_DEF 32
+#define BRIGHTNESS_MAX 63
+
+ __u8 white; /* rev12a only */
+#define WHITE_MIN 1
+#define WHITE_DEF 0x40
+#define WHITE_MAX 0x7f
+
__u8 autogain;
+#define AUTOGAIN_MIN 0
+#define AUTOGAIN_DEF 1
+#define AUTOGAIN_MAX 1
+
+ __u8 gain; /* rev12a only */
+#define GAIN_MIN 0x0
+#define GAIN_DEF 0x24
+#define GAIN_MAX 0x24
+
+#define EXPO12A_DEF 3
+ __u8 expo12a; /* expo/gain? for rev 12a */
__u8 chip_revision;
+#define Rev012A 0
+#define Rev072A 1
+
signed char ag_cnt;
#define AG_CNT_START 13
};
-/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 63,
- .step = 1,
- .default_value = 32,
- },
- .set = sd_setbrightness,
- .get = sd_getbrightness,
- },
-#define SD_CONTRAST 1
- {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 0x3fff,
- .step = 1,
- .default_value = 0x2000,
- },
- .set = sd_setcontrast,
- .get = sd_getcontrast,
- },
-#define SD_AUTOGAIN 2
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- .set = sd_setautogain,
- .get = sd_getautogain,
- },
-};
-
static struct v4l2_pix_format sif_mode[] = {
{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 160,
@@ -143,12 +122,8 @@ static struct v4l2_pix_format sif_mode[] = {
#define SPCA561_INDEX_I2C_BASE 0x8800
#define SPCA561_SNAPBIT 0x20
#define SPCA561_SNAPCTRL 0x40
-enum {
- Rev072A = 0,
- Rev012A,
-};
-static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
{
int ret;
@@ -198,12 +173,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
index, gspca_dev->usb_buf, len, 500);
}
-static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
-{
- reg_w_val(gspca_dev->dev, 0x92, 0x8804);
- reg_w_val(gspca_dev->dev, mode, 0x8802);
-}
-
static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
{
int retry = 60;
@@ -212,9 +181,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
DataLow = valeur;
DataHight = valeur >> 8;
- reg_w_val(gspca_dev->dev, reg, 0x8801);
- reg_w_val(gspca_dev->dev, DataLow, 0x8805);
- reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+ reg_w_val(gspca_dev->dev, 0x8801, reg);
+ reg_w_val(gspca_dev->dev, 0x8805, DataLow);
+ reg_w_val(gspca_dev->dev, 0x8800, DataHight);
while (retry--) {
reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf[0])
@@ -228,9 +197,9 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
__u8 value;
__u8 vallsb;
- reg_w_val(gspca_dev->dev, 0x92, 0x8804);
- reg_w_val(gspca_dev->dev, reg, 0x8801);
- reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
+ reg_w_val(gspca_dev->dev, 0x8804, 0x92);
+ reg_w_val(gspca_dev->dev, 0x8801, reg);
+ reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
while (retry--) {
reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf)
@@ -438,10 +407,11 @@ static const __u16 spca561_init_data[][2] = {
{0x0035, 0x8801}, /* 0x14 - set gain general */
{0x001f, 0x8805}, /* 0x14 */
{0x0000, 0x8800},
- {0x0030, 0x8112},
+ {0x000e, 0x8112}, /* white balance - was 30 */
{}
};
+#if 0
static void sensor_reset(struct gspca_dev *gspca_dev)
{
reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
@@ -449,10 +419,12 @@ static void sensor_reset(struct gspca_dev *gspca_dev)
reg_w_val(gspca_dev->dev, 0x8112, 0x00);
reg_w_val(gspca_dev->dev, 0x8114, 0x00);
reg_w_val(gspca_dev->dev, 0x8118, 0x21);
- i2c_init(gspca_dev, 0x14);
- i2c_write(gspca_dev, 1, 0x0d);
- i2c_write(gspca_dev, 0, 0x0d);
+ reg_w_val(gspca_dev->dev, 0x8804, 0x92); /* i2c init */
+ reg_w_val(gspca_dev->dev, 0x8802, 0x14);
+ i2c_write(gspca_dev, 0x0001, 0x0d);
+ i2c_write(gspca_dev, 0x0000, 0x0d);
}
+#endif
/******************** QC Express etch2 stuff ********************/
static const __u16 Pb100_1map8300[][2] = {
@@ -462,9 +434,9 @@ static const __u16 Pb100_1map8300[][2] = {
{0x8303, 0x0125}, /* image area */
{0x8304, 0x0169},
{0x8328, 0x000b},
- {0x833c, 0x0001},
+ {0x833c, 0x0001}, /*fixme: win:07*/
- {0x832f, 0x0419},
+ {0x832f, 0x1904}, /*fixme: was 0419*/
{0x8307, 0x00aa},
{0x8301, 0x0003},
{0x8302, 0x000e},
@@ -478,9 +450,10 @@ static const __u16 Pb100_2map8300[][2] = {
};
static const __u16 spca561_161rev12A_data1[][2] = {
- {0x21, 0x8118},
- {0x01, 0x8114},
- {0x00, 0x8112},
+ {0x29, 0x8118}, /* white balance - was 21 */
+ {0x08, 0x8114}, /* white balance - was 01 */
+ {0x0e, 0x8112}, /* white balance - was 00 */
+ {0x00, 0x8102}, /* white balance - new */
{0x92, 0x8804},
{0x04, 0x8802}, /* windows uses 08 */
{}
@@ -505,14 +478,16 @@ static const __u16 spca561_161rev12A_data2[][2] = {
{0xb0, 0x8603},
/* sensor gains */
+ {0x07, 0x8601}, /* white balance - new */
+ {0x07, 0x8602}, /* white balance - new */
{0x00, 0x8610}, /* *red */
{0x00, 0x8611}, /* 3f *green */
{0x00, 0x8612}, /* green *blue */
{0x00, 0x8613}, /* blue *green */
- {0x35, 0x8614}, /* green *red */
- {0x35, 0x8615}, /* 40 *green */
- {0x35, 0x8616}, /* 7a *blue */
- {0x35, 0x8617}, /* 40 *green */
+ {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
+ {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
+ {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
+ {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
{0x0c, 0x8620}, /* 0c */
{0xc8, 0x8631}, /* c8 */
@@ -527,6 +502,7 @@ static const __u16 spca561_161rev12A_data2[][2] = {
{0xdf, 0x863c}, /* df */
{0xf0, 0x8505},
{0x32, 0x850a},
+/* {0x99, 0x8700}, * - white balance - new (removed) */
{}
};
@@ -545,9 +521,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev,
}
static void init_161rev12A(struct gspca_dev *gspca_dev)
{
- sensor_reset(gspca_dev);
+/* sensor_reset(gspca_dev); (not in win) */
write_vector(gspca_dev, spca561_161rev12A_data1);
sensor_mapwrite(gspca_dev, Pb100_1map8300);
+/*fixme: should be in sd_start*/
write_vector(gspca_dev, spca561_161rev12A_data2);
sensor_mapwrite(gspca_dev, Pb100_2map8300);
}
@@ -581,35 +558,33 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam = &gspca_dev->cam;
- cam->dev_name = (char *) id->driver_info;
cam->epaddr = 0x01;
gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
cam->cam_mode = sif_mode;
- cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ cam->nmodes = ARRAY_SIZE(sif_mode);
sd->chip_revision = id->driver_info;
- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
- sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
- sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->white = WHITE_DEF;
+ sd->exposure = EXPOSURE_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ sd->gain = GAIN_DEF;
+ sd->expo12a = EXPO12A_DEF;
return 0;
}
/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+static int sd_open_12a(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
- switch (sd->chip_revision) {
- case Rev072A:
- PDEBUG(D_STREAM, "Chip revision id: 072a");
- write_vector(gspca_dev, spca561_init_data);
- break;
- default:
-/* case Rev012A: */
- PDEBUG(D_STREAM, "Chip revision id: 012a");
- init_161rev12A(gspca_dev);
- break;
- }
+ PDEBUG(D_STREAM, "Chip revision: 012a");
+ init_161rev12A(gspca_dev);
+ return 0;
+}
+static int sd_open_72a(struct gspca_dev *gspca_dev)
+{
+ PDEBUG(D_STREAM, "Chip revision: 072a");
+ write_vector(gspca_dev, spca561_init_data);
return 0;
}
@@ -618,25 +593,20 @@ static void setcontrast(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
__u8 lowb;
- int expotimes;
switch (sd->chip_revision) {
case Rev072A:
lowb = sd->contrast >> 8;
- reg_w_val(dev, lowb, 0x8651);
- reg_w_val(dev, lowb, 0x8652);
- reg_w_val(dev, lowb, 0x8653);
- reg_w_val(dev, lowb, 0x8654);
+ reg_w_val(dev, 0x8651, lowb);
+ reg_w_val(dev, 0x8652, lowb);
+ reg_w_val(dev, 0x8653, lowb);
+ reg_w_val(dev, 0x8654, lowb);
break;
- case Rev012A: {
- __u8 Reg8391[] =
- { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
-
- /* Write camera sensor settings */
- expotimes = (sd->contrast >> 5) & 0x07ff;
- Reg8391[0] = expotimes & 0xff; /* exposure */
- Reg8391[1] = 0x18 | (expotimes >> 8);
- Reg8391[2] = sd->brightness; /* gain */
+ default: {
+/* case Rev012A: { */
+ static const __u8 Reg8391[] =
+ { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
break;
@@ -644,87 +614,139 @@ static void setcontrast(struct gspca_dev *gspca_dev)
}
}
-static void setautogain(struct gspca_dev *gspca_dev)
+/* rev12a only */
+static void setwhite(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ __u16 white;
+ __u8 reg8614, reg8616;
+
+ white = sd->white;
+ /* try to emulate MS-win as possible */
+ reg8616 = 0x90 - white * 5 / 8;
+ reg_w_val(gspca_dev->dev, 0x8616, reg8616);
+ reg8614 = 0x20 + white * 3 / 8;
+ reg_w_val(gspca_dev->dev, 0x8614, reg8614);
+}
- if (sd->chip_revision == Rev072A) {
- if (sd->autogain)
- sd->ag_cnt = AG_CNT_START;
- else
- sd->ag_cnt = -1;
- }
+/* rev 12a only */
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int expo;
+ __u8 data[2];
+
+ expo = sd->exposure + 0x20a8; /* from test */
+ data[0] = expo;
+ data[1] = expo >> 8;
+ reg_w_buf(gspca_dev, 0x8309, data, 2);
}
-static void sd_start(struct gspca_dev *gspca_dev)
+/* rev 12a only */
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data[2];
+
+ data[0] = sd->gain;
+ data[1] = 0;
+ reg_w_buf(gspca_dev, 0x8335, data, 2);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->autogain)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+}
+
+static void sd_start_12a(struct gspca_dev *gspca_dev)
+{
struct usb_device *dev = gspca_dev->dev;
int Clck;
__u8 Reg8307[] = { 0xaa, 0x00 };
int mode;
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- switch (sd->chip_revision) {
- case Rev072A:
- switch (mode) {
- default:
-/* case 0:
- case 1: */
- Clck = 0x25;
- break;
- case 2:
- Clck = 0x22;
- break;
- case 3:
- Clck = 0x21;
- break;
- }
- reg_w_val(dev, 0x8500, mode); /* mode */
- reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
- reg_w_val(dev, 0x8112, 0x10 | 0x20);
- setautogain(gspca_dev);
+ switch (mode) {
+ case 0:
+ case 1:
+ Clck = 0x8a;
+ break;
+ case 2:
+ Clck = 0x85;
break;
default:
-/* case Rev012A: */
- switch (mode) {
- case 0:
- case 1:
- Clck = 0x8a;
- break;
- case 2:
- Clck = 0x85;
- break;
- default:
- Clck = 0x83;
- break;
- }
- if (mode <= 1) {
- /* Use compression on 320x240 and above */
- reg_w_val(dev, 0x8500, 0x10 | mode);
- } else {
- /* I couldn't get the compression to work below 320x240
- * Fortunately at these resolutions the bandwidth
- * is sufficient to push raw frames at ~20fps */
- reg_w_val(dev, 0x8500, mode);
- } /* -- qq@kuku.eu.org */
- reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
- reg_w_val(gspca_dev->dev, 0x8700, Clck);
- /* 0x8f 0x85 0x27 clock */
- reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
- reg_w_val(gspca_dev->dev, 0x850b, 0x03);
- setcontrast(gspca_dev);
+ Clck = 0x83;
break;
}
+ if (mode <= 1) {
+ /* Use compression on 320x240 and above */
+ reg_w_val(dev, 0x8500, 0x10 | mode);
+ } else {
+ /* I couldn't get the compression to work below 320x240
+ * Fortunately at these resolutions the bandwidth
+ * is sufficient to push raw frames at ~20fps */
+ reg_w_val(dev, 0x8500, mode);
+ } /* -- qq@kuku.eu.org */
+ reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
+ reg_w_val(gspca_dev->dev, 0x8700, Clck);
+ /* 0x8f 0x85 0x27 clock */
+ reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
+ reg_w_val(gspca_dev->dev, 0x850b, 0x03);
+ setcontrast(gspca_dev);
+ setwhite(gspca_dev);
+ setautogain(gspca_dev);
+}
+static void sd_start_72a(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int Clck;
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (mode) {
+ default:
+/* case 0:
+ case 1: */
+ Clck = 0x25;
+ break;
+ case 2:
+ Clck = 0x22;
+ break;
+ case 3:
+ Clck = 0x21;
+ break;
+ }
+ reg_w_val(dev, 0x8500, mode); /* mode */
+ reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
+ reg_w_val(dev, 0x8112, 0x10 | 0x20);
+ setautogain(gspca_dev);
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->chip_revision == Rev012A) {
+ reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
+ } else {
+ reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
+ }
}
static void sd_stop0(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->chip_revision == Rev012A) {
+ reg_w_val(gspca_dev->dev, 0x8118, 0x29);
+ reg_w_val(gspca_dev->dev, 0x8114, 0x08);
+ }
}
/* this function is called at close time */
@@ -744,6 +766,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
__u8 luma_mean = 110;
__u8 luma_delta = 20;
__u8 spring = 4;
+ __u8 reg8339[2];
if (sd->ag_cnt < 0)
return;
@@ -798,13 +821,16 @@ static void do_autogain(struct gspca_dev *gspca_dev)
}
break;
case Rev012A:
- /* sensor registers is access and memory mapped to 0x8300 */
- /* readind all 0x83xx block the sensor */
- /*
- * The data from the header seem wrong where is the luma
- * and chroma mean value
- * at the moment set exposure in contrast set
- */
+ reg_r(gspca_dev, 0x8330, 2);
+ if (gspca_dev->usb_buf[1] > 0x08) {
+ reg8339[0] = ++sd->expo12a;
+ reg8339[1] = 0;
+ reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+ } else if (gspca_dev->usb_buf[1] < 0x02) {
+ reg8339[0] = --sd->expo12a;
+ reg8339[1] = 0;
+ reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+ }
break;
}
}
@@ -841,24 +867,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
+/* rev 72a only */
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 value;
- switch (sd->chip_revision) {
- case Rev072A:
- value = sd->brightness;
- reg_w_val(gspca_dev->dev, value, 0x8611);
- reg_w_val(gspca_dev->dev, value, 0x8612);
- reg_w_val(gspca_dev->dev, value, 0x8613);
- reg_w_val(gspca_dev->dev, value, 0x8614);
- break;
- default:
-/* case Rev012A: */
- setcontrast(gspca_dev);
- break;
- }
+ value = sd->brightness;
+ reg_w_val(gspca_dev->dev, 0x8611, value);
+ reg_w_val(gspca_dev->dev, 0x8612, value);
+ reg_w_val(gspca_dev->dev, 0x8613, value);
+ reg_w_val(gspca_dev->dev, 0x8614, value);
}
static void getbrightness(struct gspca_dev *gspca_dev)
@@ -866,52 +885,38 @@ static void getbrightness(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
__u16 tot;
- switch (sd->chip_revision) {
- case Rev072A:
- tot = 0;
- reg_r(gspca_dev, 0x8611, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8612, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8613, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8614, 1);
- tot += gspca_dev->usb_buf[0];
- sd->brightness = tot >> 2;
- break;
- default:
-/* case Rev012A: */
- /* no way to read sensor settings */
- break;
- }
+ tot = 0;
+ reg_r(gspca_dev, 0x8611, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8612, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8613, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8614, 1);
+ tot += gspca_dev->usb_buf[0];
+ sd->brightness = tot >> 2;
}
+/* rev72a only */
static void getcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u16 tot;
- switch (sd->chip_revision) {
- case Rev072A:
- tot = 0;
- reg_r(gspca_dev, 0x8651, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8652, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8653, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8654, 1);
- tot += gspca_dev->usb_buf[0];
- sd->contrast = tot << 6;
- break;
- default:
-/* case Rev012A: */
- /* no way to read sensor settings */
- break;
- }
+ tot = 0;
+ reg_r(gspca_dev, 0x8651, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8652, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8653, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8654, 1);
+ tot += gspca_dev->usb_buf[0];
+ sd->contrast = tot << 6;
PDEBUG(D_CONF, "get contrast %d", sd->contrast);
}
+/* rev 72a only */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -931,6 +936,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+/* rev 72a only */
static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -968,20 +974,192 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+/* rev12a only */
+static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->white = val;
+ if (gspca_dev->streaming)
+ setwhite(gspca_dev);
+ return 0;
+}
+
+static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->white;
+ return 0;
+}
+
+/* rev12a only */
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+/* rev12a only */
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+
+/* control tables */
+static struct ctrl sd_ctrls_12a[] = {
+ {
+ {
+ .id = V4L2_CID_DO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "While Balance",
+ .minimum = WHITE_MIN,
+ .maximum = WHITE_MAX,
+ .step = 1,
+ .default_value = WHITE_DEF,
+ },
+ .set = sd_setwhite,
+ .get = sd_getwhite,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = EXPOSURE_MIN,
+ .maximum = EXPOSURE_MAX,
+ .step = 1,
+ .default_value = EXPOSURE_DEF,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = AUTOGAIN_MIN,
+ .maximum = AUTOGAIN_MAX,
+ .step = 1,
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = GAIN_MIN,
+ .maximum = GAIN_MAX,
+ .step = 1,
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+};
+
+static struct ctrl sd_ctrls_72a[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = BRIGHTNESS_MIN,
+ .maximum = BRIGHTNESS_MAX,
+ .step = 1,
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = CONTRAST_MIN,
+ .maximum = CONTRAST_MAX,
+ .step = 1,
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = AUTOGAIN_MIN,
+ .maximum = AUTOGAIN_MAX,
+ .step = 1,
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
/* sub-driver description */
-static const struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc_12a = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
+ .ctrls = sd_ctrls_12a,
+ .nctrls = ARRAY_SIZE(sd_ctrls_12a),
.config = sd_config,
- .open = sd_open,
- .start = sd_start,
+ .open = sd_open_12a,
+ .start = sd_start_12a,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+/* .dq_callback = do_autogain, * fixme */
+};
+static const struct sd_desc sd_desc_72a = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls_72a,
+ .nctrls = ARRAY_SIZE(sd_ctrls_72a),
+ .config = sd_config,
+ .open = sd_open_72a,
+ .start = sd_start_72a,
.stopN = sd_stopN,
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};
+static const struct sd_desc *sd_desc[2] = {
+ &sd_desc_12a,
+ &sd_desc_72a
+};
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
@@ -1009,7 +1187,9 @@ MODULE_DEVICE_TABLE(usb, device_table);
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),
+ return gspca_dev_probe(intf, id,
+ sd_desc[id->driver_info],
+ sizeof(struct sd),
THIS_MODULE);
}
@@ -1018,6 +1198,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c
index 16219cf6a..387a8cf2b 100644
--- a/linux/drivers/media/video/gspca/stk014.c
+++ b/linux/drivers/media/video/gspca/stk014.c
@@ -564,6 +564,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c
index 8701b07c8..e1a7e53ba 100644
--- a/linux/drivers/media/video/gspca/sunplus.c
+++ b/linux/drivers/media/video/gspca/sunplus.c
@@ -1487,6 +1487,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c
index 56b1dfa72..27bff51a0 100644
--- a/linux/drivers/media/video/gspca/t613.c
+++ b/linux/drivers/media/video/gspca/t613.c
@@ -30,7 +30,7 @@
#define MAX_GAMMA 0x10 /* 0 to 15 */
-#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
@@ -233,7 +233,7 @@ static char *effects_control[] = {
static struct v4l2_pix_format vga_mode_t16[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
- .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 4},
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -1037,6 +1037,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c
index fcac077bb..c55dbe8ac 100644
--- a/linux/drivers/media/video/gspca/tv8532.c
+++ b/linux/drivers/media/video/gspca/tv8532.c
@@ -653,6 +653,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
index 0e23edb16..f37c63d6d 100644
--- a/linux/drivers/media/video/gspca/vc032x.c
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -1971,6 +1971,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c
index ff0c30e4a..a3f109ac4 100644
--- a/linux/drivers/media/video/gspca/zc3xx.c
+++ b/linux/drivers/media/video/gspca/zc3xx.c
@@ -70,6 +70,10 @@ struct sd {
unsigned short chip_revision;
};
+#define DRIVER_INFO(sensor, flags) .driver_info = ((sensor) << 8) | (flags)
+#define DRIVER_INFO_GET_SENSOR(driver_info) ((driver_info) >> 8)
+#define DRIVER_INFO_GET_FLAGS(driver_info) ((driver_info) & 0xff)
+
/* V4L2 controls supported by the driver */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
@@ -6969,8 +6973,13 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
case SENSOR_MC501CB:
return -1; /* don't probe */
case SENSOR_TAS5130C_VF0250:
- /* may probe but with write in reg 0x0010 */
+ /* may probe but with no write in reg 0x0010 */
return -1; /* don't probe */
+ case SENSOR_PAS106:
+ sensor = sif_probe(gspca_dev);
+ if (sensor >= 0)
+ return sensor;
+ break;
}
sensor = vga_2wr_probe(gspca_dev);
if (sensor >= 0) {
@@ -6979,12 +6988,10 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
/* next probe is needed for OmniVision ? */
}
sensor2 = vga_3wr_probe(gspca_dev);
- if (sensor2 >= 0) {
- if (sensor >= 0)
- return sensor;
- return sensor2;
- }
- return sif_probe(gspca_dev);
+ if (sensor2 >= 0
+ && sensor >= 0)
+ return sensor;
+ return sensor2;
}
/* this function is called at probe time */
@@ -7017,7 +7024,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* define some sensors from the vendor/product */
sd->sharpness = 2;
- sd->sensor = id->driver_info;
+ sd->sensor = DRIVER_INFO_GET_SENSOR(id->driver_info);
+ gspca_dev->flags = DRIVER_INFO_GET_FLAGS(id->driver_info);
sensor = zcxx_probeSensor(gspca_dev);
if (sensor >= 0)
PDEBUG(D_PROBE, "probe sensor -> %02x", sensor);
@@ -7514,19 +7522,19 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x041e)},
#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x041e, 0x4017)},
- {USB_DEVICE(0x041e, 0x401c)},
+ {USB_DEVICE(0x041e, 0x401c), DRIVER_INFO(SENSOR_PAS106, 0)},
{USB_DEVICE(0x041e, 0x401e)},
{USB_DEVICE(0x041e, 0x401f)},
#endif
{USB_DEVICE(0x041e, 0x4029)},
#ifndef CONFIG_USB_ZC0301
- {USB_DEVICE(0x041e, 0x4034)},
- {USB_DEVICE(0x041e, 0x4035)},
+ {USB_DEVICE(0x041e, 0x4034), DRIVER_INFO(SENSOR_PAS106, 0)},
+ {USB_DEVICE(0x041e, 0x4035), DRIVER_INFO(SENSOR_PAS106, 0)},
{USB_DEVICE(0x041e, 0x4036)},
{USB_DEVICE(0x041e, 0x403a)},
#endif
- {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250},
- {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250},
+ {USB_DEVICE(0x041e, 0x4051), DRIVER_INFO(SENSOR_TAS5130C_VF0250, 0)},
+ {USB_DEVICE(0x041e, 0x4053), DRIVER_INFO(SENSOR_TAS5130C_VF0250, 0)},
#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x0458, 0x7007)},
{USB_DEVICE(0x0458, 0x700c)},
@@ -7552,11 +7560,13 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x08d9)},
{USB_DEVICE(0x046d, 0x08d8)},
{USB_DEVICE(0x046d, 0x08da)},
- {USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB},
- {USB_DEVICE(0x0471, 0x0325)},
- {USB_DEVICE(0x0471, 0x0326)},
- {USB_DEVICE(0x0471, 0x032d)},
- {USB_DEVICE(0x0471, 0x032e)},
+ {USB_DEVICE(0x046d, 0x08dd), DRIVER_INFO(SENSOR_MC501CB, 0)},
+ {USB_DEVICE(0x0471, 0x0325), DRIVER_INFO(SENSOR_PAS106,
+ GSPCA_SENSOR_UPSIDE_DOWN_FLAG)},
+ {USB_DEVICE(0x0471, 0x0326), DRIVER_INFO(SENSOR_PAS106,
+ GSPCA_SENSOR_UPSIDE_DOWN_FLAG)},
+ {USB_DEVICE(0x0471, 0x032d), DRIVER_INFO(SENSOR_PAS106, 0)},
+ {USB_DEVICE(0x0471, 0x032e), DRIVER_INFO(SENSOR_PAS106, 0)},
{USB_DEVICE(0x055f, 0xc005)},
#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x055f, 0xd003)},
@@ -7568,7 +7578,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0ac8, 0x301b)},
{USB_DEVICE(0x0ac8, 0x303b)},
#endif
- {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},
+ {USB_DEVICE(0x0ac8, 0x305b), DRIVER_INFO(SENSOR_TAS5130C_VF0250, 0)},
#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x0ac8, 0x307b)},
{USB_DEVICE(0x10fd, 0x0128)},
@@ -7593,6 +7603,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
static int __init sd_mod_init(void)
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c
index efdb59193..89a16bfeb 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -688,7 +688,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
spin_lock_init(&itv->lock);
spin_lock_init(&itv->dma_reg_lock);
- itv->irq_work_queues = create_workqueue(itv->name);
+ itv->irq_work_queues = create_singlethread_workqueue(itv->name);
if (itv->irq_work_queues == NULL) {
IVTV_ERR("Could not create ivtv workqueue\n");
return -1;
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h
index d66ee14b6..6e0ca223a 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.h
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.h
@@ -252,6 +252,7 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */
#define IVTV_F_I_INITED 21 /* set after first open */
#define IVTV_F_I_FAILED 22 /* set if first open failed */
+#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */
/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */
diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c
index d5ac766c1..59fe56171 100644
--- a/linux/drivers/media/video/ivtv/ivtv-irq.c
+++ b/linux/drivers/media/video/ivtv/ivtv-irq.c
@@ -82,6 +82,13 @@ void ivtv_irq_work_handler(void *arg)
DEFINE_WAIT(wait);
+ if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) {
+ struct sched_param param = { .sched_priority = 99 };
+
+ /* This thread must use the FIFO scheduler as it
+ is realtime sensitive. */
+ sched_setscheduler(current, SCHED_FIFO, &param);
+ }
if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
ivtv_pio_work_handler(itv);
@@ -684,34 +691,14 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
{
- struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- /* If more than two VBI buffers are pending, then
- clear the old ones and start with this new one.
- This can happen during transition stages when MPEG capturing is
- started, but the first interrupts haven't arrived yet. During
- that period VBI requests can accumulate without being able to
- DMA the data. Since at most four VBI DMA buffers are available,
- we just drop the old requests when there are already three
- requests queued. */
- if (s->sg_pending_size > 2) {
- struct ivtv_buffer *buf;
- list_for_each_entry(buf, &s->q_predma.list, list)
- ivtv_buf_sync_for_cpu(s, buf);
- ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
- s->sg_pending_size = 0;
- }
- /* if we can append the data, and the MPEG stream isn't capturing,
- then start a DMA request for just the VBI data. */
- if (!stream_enc_dma_append(s, data) &&
- !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
+ if (!stream_enc_dma_append(s, data))
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
- }
}
static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.h b/linux/drivers/media/video/ivtv/ivtv-queue.h
index 7cfc0c9ab..476556afd 100644
--- a/linux/drivers/media/video/ivtv/ivtv-queue.h
+++ b/linux/drivers/media/video/ivtv/ivtv-queue.h
@@ -23,7 +23,7 @@
#define IVTV_QUEUE_H
#define IVTV_DMA_UNMAPPED ((u32) -1)
-#define SLICED_VBI_PIO 1
+#define SLICED_VBI_PIO 0
/* ivtv_buffer utility functions */
diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c
index 54d2023b2..730e85d86 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -363,7 +363,7 @@ static void ivtv_vbi_setup(struct ivtv *itv)
/* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
data[1] = 1;
/* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
- data[2] = raw ? 4 : 8;
+ data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
/* The start/stop codes determine which VBI lines end up in the raw VBI data area.
The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
diff --git a/linux/drivers/media/video/ivtv/ivtv-vbi.c b/linux/drivers/media/video/ivtv/ivtv-vbi.c
index 71798f0da..1ce9deb11 100644
--- a/linux/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/linux/drivers/media/video/ivtv/ivtv-vbi.c
@@ -293,6 +293,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
u32 line_size = itv->vbi.sliced_decoder_line_size;
struct v4l2_decode_vbi_line vbi;
int i;
+ unsigned lines = 0;
/* find the first valid line */
for (i = 0; i < size; i++, buf++) {
@@ -313,7 +314,8 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
}
vbi.p = p + 4;
itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
- if (vbi.type) {
+ if (vbi.type && !(lines & (1 << vbi.line))) {
+ lines |= 1 << vbi.line;
itv->vbi.sliced_data[line].id = vbi.type;
itv->vbi.sliced_data[line].field = vbi.is_second_field;
itv->vbi.sliced_data[line].line = vbi.line;
diff --git a/linux/drivers/media/video/ivtv/ivtv-version.h b/linux/drivers/media/video/ivtv/ivtv-version.h
index 442f43f11..8cd753d30 100644
--- a/linux/drivers/media/video/ivtv/ivtv-version.h
+++ b/linux/drivers/media/video/ivtv/ivtv-version.h
@@ -22,7 +22,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 3
+#define IVTV_DRIVER_VERSION_MINOR 4
#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/linux/drivers/media/video/ks0127.c b/linux/drivers/media/video/ks0127.c
index 90451230d..b21b6f097 100644
--- a/linux/drivers/media/video/ks0127.c
+++ b/linux/drivers/media/video/ks0127.c
@@ -680,26 +680,27 @@ static int ks0127_command(struct i2c_client *client,
case DECODER_ENABLE_OUTPUT:
{
+ int enable;
- int *iarg = arg;
- int enable = (*iarg != 0);
- if (enable) {
- dprintk("ks0127: command "
+ iarg = arg;
+ enable = (*iarg != 0);
+ if (enable) {
+ dprintk("ks0127: command "
"DECODER_ENABLE_OUTPUT on "
"(%d)\n", enable);
- /* All output pins on */
- ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
- /* Obey the OEN pin */
- ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
- } else {
- dprintk("ks0127: command "
+ /* All output pins on */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+ /* Obey the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+ } else {
+ dprintk("ks0127: command "
"DECODER_ENABLE_OUTPUT off "
"(%d)\n", enable);
- /* Video output pins off */
- ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
- /* Ignore the OEN pin */
- ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
- }
+ /* Video output pins off */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+ /* Ignore the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+ }
}
break;
diff --git a/linux/drivers/media/video/meye.c b/linux/drivers/media/video/meye.c
index a0cdae0c1..331cb6d1f 100644
--- a/linux/drivers/media/video/meye.c
+++ b/linux/drivers/media/video/meye.c
@@ -1784,6 +1784,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
goto outnotdev;
}
+ ret = -ENOMEM;
meye.mchip_dev = pcidev;
meye.video_dev = video_device_alloc();
if (!meye.video_dev) {
@@ -1791,7 +1792,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
goto outnotdev;
}
- ret = -ENOMEM;
meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE);
if (!meye.grab_temp) {
printk(KERN_ERR "meye: grab buffer allocation failed\n");
@@ -1816,6 +1816,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
meye.video_dev->parent = &meye.mchip_dev->dev;
+ ret = -EIO;
if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
printk(KERN_ERR "meye: unable to power on the camera\n");
printk(KERN_ERR "meye: did you enable the camera in "
@@ -1823,7 +1824,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
goto outsonypienable;
}
- ret = -EIO;
if ((ret = pci_enable_device(meye.mchip_dev))) {
printk(KERN_ERR "meye: pci_enable_device failed\n");
goto outenabledev;
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index f4742936c..228183c54 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -117,24 +117,51 @@ static int reg_clear(struct soc_camera_device *icd, const u8 reg,
static int mt9m001_init(struct soc_camera_device *icd)
{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
int ret;
- /* Disable chip, synchronous option update */
dev_dbg(icd->vdev->parent, "%s\n", __func__);
- ret = reg_write(icd, MT9M001_RESET, 1);
- if (ret >= 0)
- ret = reg_write(icd, MT9M001_RESET, 0);
- if (ret >= 0)
+ if (icl->power) {
+ ret = icl->power(&mt9m001->client->dev, 1);
+ if (ret < 0) {
+ dev_err(icd->vdev->parent,
+ "Platform failed to power-on the camera.\n");
+ return ret;
+ }
+ }
+
+ /* The camera could have been already on, we reset it additionally */
+ if (icl->reset)
+ ret = icl->reset(&mt9m001->client->dev);
+ else
+ ret = -ENODEV;
+
+ if (ret < 0) {
+ /* Either no platform reset, or platform reset failed */
+ ret = reg_write(icd, MT9M001_RESET, 1);
+ if (!ret)
+ ret = reg_write(icd, MT9M001_RESET, 0);
+ }
+ /* Disable chip, synchronous option update */
+ if (!ret)
ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
- return ret >= 0 ? 0 : -EIO;
+ return ret;
}
static int mt9m001_release(struct soc_camera_device *icd)
{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+
/* Disable the chip */
reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+
+ if (icl->power)
+ icl->power(&mt9m001->client->dev, 0);
+
return 0;
}
@@ -267,24 +294,24 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
/* Blanking and start values - default... */
ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
/* The caller provides a supported format, as verified per
* call to icd->try_fmt_cap() */
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9M001_ROW_START, rect->top);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9M001_WINDOW_HEIGHT,
rect->height + icd->y_skip_top - 1);
- if (ret >= 0 && mt9m001->autoexposure) {
+ if (!ret && mt9m001->autoexposure) {
ret = reg_write(icd, MT9M001_SHUTTER_WIDTH,
rect->height + icd->y_skip_top + vblank);
- if (ret >= 0) {
+ if (!ret) {
const struct v4l2_queryctrl *qctrl =
soc_camera_find_qctrl(icd->ops,
V4L2_CID_EXPOSURE);
@@ -295,7 +322,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
}
}
- return ret < 0 ? ret : 0;
+ return ret;
}
static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c
new file mode 100644
index 000000000..e4ec7538d
--- /dev/null
+++ b/linux/drivers/media/video/mt9m111.c
@@ -0,0 +1,981 @@
+/*
+ * Driver for MT9M111 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * 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/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+/*
+ * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin)
+ * The platform has to define i2c_board_info and call i2c_register_board_info()
+ */
+
+/* mt9m111: Sensor register addresses */
+#define MT9M111_CHIP_VERSION 0x000
+#define MT9M111_ROW_START 0x001
+#define MT9M111_COLUMN_START 0x002
+#define MT9M111_WINDOW_HEIGHT 0x003
+#define MT9M111_WINDOW_WIDTH 0x004
+#define MT9M111_HORIZONTAL_BLANKING_B 0x005
+#define MT9M111_VERTICAL_BLANKING_B 0x006
+#define MT9M111_HORIZONTAL_BLANKING_A 0x007
+#define MT9M111_VERTICAL_BLANKING_A 0x008
+#define MT9M111_SHUTTER_WIDTH 0x009
+#define MT9M111_ROW_SPEED 0x00a
+#define MT9M111_EXTRA_DELAY 0x00b
+#define MT9M111_SHUTTER_DELAY 0x00c
+#define MT9M111_RESET 0x00d
+#define MT9M111_READ_MODE_B 0x020
+#define MT9M111_READ_MODE_A 0x021
+#define MT9M111_FLASH_CONTROL 0x023
+#define MT9M111_GREEN1_GAIN 0x02b
+#define MT9M111_BLUE_GAIN 0x02c
+#define MT9M111_RED_GAIN 0x02d
+#define MT9M111_GREEN2_GAIN 0x02e
+#define MT9M111_GLOBAL_GAIN 0x02f
+#define MT9M111_CONTEXT_CONTROL 0x0c8
+#define MT9M111_PAGE_MAP 0x0f0
+#define MT9M111_BYTE_WISE_ADDR 0x0f1
+
+#define MT9M111_RESET_SYNC_CHANGES (1 << 15)
+#define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9)
+#define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8)
+#define MT9M111_RESET_RESET_SOC (1 << 5)
+#define MT9M111_RESET_OUTPUT_DISABLE (1 << 4)
+#define MT9M111_RESET_CHIP_ENABLE (1 << 3)
+#define MT9M111_RESET_ANALOG_STANDBY (1 << 2)
+#define MT9M111_RESET_RESTART_FRAME (1 << 1)
+#define MT9M111_RESET_RESET_MODE (1 << 0)
+
+#define MT9M111_RMB_MIRROR_COLS (1 << 1)
+#define MT9M111_RMB_MIRROR_ROWS (1 << 0)
+#define MT9M111_CTXT_CTRL_RESTART (1 << 15)
+#define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12)
+#define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10)
+#define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9)
+#define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8)
+#define MT9M111_CTXT_CTRL_XENON_EN (1 << 7)
+#define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3)
+#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2)
+#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1)
+#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0)
+/*
+ * mt9m111: Colorpipe register addresses (0x100..0x1ff)
+ */
+#define MT9M111_OPER_MODE_CTRL 0x106
+#define MT9M111_OUTPUT_FORMAT_CTRL 0x108
+#define MT9M111_REDUCER_XZOOM_B 0x1a0
+#define MT9M111_REDUCER_XSIZE_B 0x1a1
+#define MT9M111_REDUCER_YZOOM_B 0x1a3
+#define MT9M111_REDUCER_YSIZE_B 0x1a4
+#define MT9M111_REDUCER_XZOOM_A 0x1a6
+#define MT9M111_REDUCER_XSIZE_A 0x1a7
+#define MT9M111_REDUCER_YZOOM_A 0x1a9
+#define MT9M111_REDUCER_YSIZE_A 0x1aa
+
+#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a
+#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b
+
+#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14)
+
+
+#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
+#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10)
+#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9)
+#define MT9M111_OUTFMT_RGB (1 << 8)
+#define MT9M111_OUTFMT_RGB565 (0x0 << 6)
+#define MT9M111_OUTFMT_RGB555 (0x1 << 6)
+#define MT9M111_OUTFMT_RGB444x (0x2 << 6)
+#define MT9M111_OUTFMT_RGBx444 (0x3 << 6)
+#define MT9M111_OUTFMT_TST_RAMP_OFF (0x0 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_COL (0x1 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_ROW (0x2 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_FRAME (0x3 << 4)
+#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3)
+#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2)
+#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y (1 << 1)
+#define MT9M111_OUTFMT_SWAP_RGB_EVEN (1 << 1)
+#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr (1 << 0)
+/*
+ * mt9m111: Camera control register addresses (0x200..0x2ff not implemented)
+ */
+
+#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg)
+#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val))
+#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val))
+#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val))
+
+#define MT9M111_MIN_DARK_ROWS 8
+#define MT9M111_MIN_DARK_COLS 24
+#define MT9M111_MAX_HEIGHT 1024
+#define MT9M111_MAX_WIDTH 1280
+
+#define COL_FMT(_name, _depth, _fourcc, _colorspace) \
+ { .name = _name, .depth = _depth, .fourcc = _fourcc, \
+ .colorspace = _colorspace }
+#define RGB_FMT(_name, _depth, _fourcc) \
+ COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB)
+
+static const struct soc_camera_data_format mt9m111_colour_formats[] = {
+ COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG),
+ RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565),
+ RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555),
+ RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16),
+ RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8),
+};
+
+enum mt9m111_context {
+ HIGHPOWER = 0,
+ LOWPOWER,
+};
+
+struct mt9m111 {
+ struct i2c_client *client;
+ struct soc_camera_device icd;
+ int model; /* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */
+ enum mt9m111_context context;
+ unsigned int left, top, width, height;
+ u32 pixfmt;
+ unsigned char autoexposure;
+ unsigned char datawidth;
+ unsigned int powered:1;
+ unsigned int hflip:1;
+ unsigned int vflip:1;
+ unsigned int swap_rgb_even_odd:1;
+ unsigned int swap_rgb_red_blue:1;
+ unsigned int swap_yuv_y_chromas:1;
+ unsigned int swap_yuv_cb_cr:1;
+};
+
+static int reg_page_map_set(struct i2c_client *client, const u16 reg)
+{
+ int ret;
+ u16 page;
+ static int lastpage = -1; /* PageMap cache value */
+
+ page = (reg >> 8);
+ if (page == lastpage)
+ return 0;
+ if (page > 2)
+ return -EINVAL;
+
+ ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page));
+ if (!ret)
+ lastpage = page;
+ return ret;
+}
+
+static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = mt9m111->client;
+ int ret;
+
+ ret = reg_page_map_set(client, reg);
+ if (!ret)
+ ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff)));
+
+ dev_dbg(&icd->dev, "read reg.%03x -> %04x\n", reg, ret);
+ return ret;
+}
+
+static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg,
+ const u16 data)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = mt9m111->client;
+ int ret;
+
+ ret = reg_page_map_set(client, reg);
+ if (!ret)
+ ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff),
+ swab16(data));
+ dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
+ return ret;
+}
+
+static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = mt9m111_reg_read(icd, reg);
+ if (ret >= 0)
+ ret = mt9m111_reg_write(icd, reg, ret | data);
+ return ret;
+}
+
+static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = mt9m111_reg_read(icd, reg);
+ return mt9m111_reg_write(icd, reg, ret & ~data);
+}
+
+static int mt9m111_set_context(struct soc_camera_device *icd,
+ enum mt9m111_context ctxt)
+{
+ int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
+ | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
+ | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
+ | MT9M111_CTXT_CTRL_VBLANK_SEL_B
+ | MT9M111_CTXT_CTRL_HBLANK_SEL_B;
+ int valA = MT9M111_CTXT_CTRL_RESTART;
+
+ if (ctxt == HIGHPOWER)
+ return reg_write(CONTEXT_CONTROL, valB);
+ else
+ return reg_write(CONTEXT_CONTROL, valA);
+}
+
+static int mt9m111_setup_rect(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret, is_raw_format;
+ int width = mt9m111->width;
+ int height = mt9m111->height;
+
+ if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
+ || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
+ is_raw_format = 1;
+ else
+ is_raw_format = 0;
+
+ ret = reg_write(COLUMN_START, mt9m111->left);
+ if (!ret)
+ ret = reg_write(ROW_START, mt9m111->top);
+
+ if (is_raw_format) {
+ if (!ret)
+ ret = reg_write(WINDOW_WIDTH, width);
+ if (!ret)
+ ret = reg_write(WINDOW_HEIGHT, height);
+ } else {
+ if (!ret)
+ ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH);
+ if (!ret)
+ ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT);
+ if (!ret)
+ ret = reg_write(REDUCER_XSIZE_B, width);
+ if (!ret)
+ ret = reg_write(REDUCER_YSIZE_B, height);
+ if (!ret)
+ ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH);
+ if (!ret)
+ ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT);
+ if (!ret)
+ ret = reg_write(REDUCER_XSIZE_A, width);
+ if (!ret)
+ ret = reg_write(REDUCER_YSIZE_A, height);
+ }
+
+ return ret;
+}
+
+static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
+{
+ int ret;
+
+ ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
+ if (!ret)
+ ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt);
+ return ret;
+}
+
+static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd)
+{
+ return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER);
+}
+
+static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd)
+{
+ return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP);
+}
+
+static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int val = 0;
+
+ if (mt9m111->swap_rgb_red_blue)
+ val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+ if (mt9m111->swap_rgb_even_odd)
+ val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
+ val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
+
+ return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int val = 0;
+
+ if (mt9m111->swap_rgb_red_blue)
+ val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+ if (mt9m111->swap_rgb_even_odd)
+ val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
+ val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
+
+ return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int val = 0;
+
+ if (mt9m111->swap_yuv_cb_cr)
+ val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+ if (mt9m111->swap_yuv_y_chromas)
+ val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
+
+ return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_enable(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+ int ret;
+
+ if (icl->power) {
+ ret = icl->power(&mt9m111->client->dev, 1);
+ if (ret < 0) {
+ dev_err(icd->vdev->parent,
+ "Platform failed to power-on the camera.\n");
+ return ret;
+ }
+ }
+
+ ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
+ if (!ret)
+ mt9m111->powered = 1;
+ return ret;
+}
+
+static int mt9m111_disable(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+ int ret;
+
+ ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
+ if (!ret)
+ mt9m111->powered = 0;
+
+ if (icl->power)
+ icl->power(&mt9m111->client->dev, 0);
+
+ return ret;
+}
+
+static int mt9m111_reset(struct soc_camera_device *icd)
+{
+ int ret;
+
+ ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+ if (!ret)
+ ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
+ if (!ret)
+ ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
+ | MT9M111_RESET_RESET_SOC);
+ return ret;
+}
+
+static int mt9m111_start_capture(struct soc_camera_device *icd)
+{
+ return 0;
+}
+
+static int mt9m111_stop_capture(struct soc_camera_device *icd)
+{
+ return 0;
+}
+
+static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
+{
+ return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_DATAWIDTH_8;
+}
+
+static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
+{
+ return 0;
+}
+
+static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_SBGGR8:
+ ret = mt9m111_setfmt_bayer8(icd);
+ break;
+ case V4L2_PIX_FMT_SBGGR16:
+ ret = mt9m111_setfmt_bayer10(icd);
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ ret = mt9m111_setfmt_rgb555(icd);
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ ret = mt9m111_setfmt_rgb565(icd);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ ret = mt9m111_setfmt_yuv(icd);
+ break;
+ default:
+ dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt);
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ mt9m111->pixfmt = pixfmt;
+
+ return ret;
+}
+
+static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret;
+
+ mt9m111->left = rect->left;
+ mt9m111->top = rect->top;
+ mt9m111->width = rect->width;
+ mt9m111->height = rect->height;
+
+ dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
+ __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width,
+ mt9m111->height);
+
+ ret = mt9m111_setup_rect(icd);
+ if (!ret)
+ ret = mt9m111_set_pixfmt(icd, pixfmt);
+ return ret;
+}
+
+static int mt9m111_try_fmt_cap(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ if (f->fmt.pix.height > MT9M111_MAX_HEIGHT)
+ f->fmt.pix.height = MT9M111_MAX_HEIGHT;
+ if (f->fmt.pix.width > MT9M111_MAX_WIDTH)
+ f->fmt.pix.width = MT9M111_MAX_WIDTH;
+
+ return 0;
+}
+
+static int mt9m111_get_chip_id(struct soc_camera_device *icd,
+ struct v4l2_chip_ident *id)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+ if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match_chip != mt9m111->client->addr)
+ return -ENODEV;
+
+ id->ident = mt9m111->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m111_get_register(struct soc_camera_device *icd,
+ struct v4l2_register *reg)
+{
+ int val;
+
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+ if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ return -EINVAL;
+ if (reg->match_chip != mt9m111->client->addr)
+ return -ENODEV;
+
+ val = mt9m111_reg_read(icd, reg->reg);
+ reg->val = (u64)val;
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9m111_set_register(struct soc_camera_device *icd,
+ struct v4l2_register *reg)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+ if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ return -EINVAL;
+
+ if (reg->match_chip != mt9m111->client->addr)
+ return -ENODEV;
+
+ if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static const struct v4l2_queryctrl mt9m111_controls[] = {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Verticaly",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Horizontaly",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, { /* gain = 1/32*val (=>gain=1 if val==32) */
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 63 * 2 * 2,
+ .step = 1,
+ .default_value = 32,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ }
+};
+
+static int mt9m111_video_probe(struct soc_camera_device *);
+static void mt9m111_video_remove(struct soc_camera_device *);
+static int mt9m111_get_control(struct soc_camera_device *,
+ struct v4l2_control *);
+static int mt9m111_set_control(struct soc_camera_device *,
+ struct v4l2_control *);
+static int mt9m111_resume(struct soc_camera_device *icd);
+static int mt9m111_init(struct soc_camera_device *icd);
+static int mt9m111_release(struct soc_camera_device *icd);
+
+static struct soc_camera_ops mt9m111_ops = {
+ .owner = THIS_MODULE,
+ .probe = mt9m111_video_probe,
+ .remove = mt9m111_video_remove,
+ .init = mt9m111_init,
+ .resume = mt9m111_resume,
+ .release = mt9m111_release,
+ .start_capture = mt9m111_start_capture,
+ .stop_capture = mt9m111_stop_capture,
+ .set_fmt_cap = mt9m111_set_fmt_cap,
+ .try_fmt_cap = mt9m111_try_fmt_cap,
+ .query_bus_param = mt9m111_query_bus_param,
+ .set_bus_param = mt9m111_set_bus_param,
+ .controls = mt9m111_controls,
+ .num_controls = ARRAY_SIZE(mt9m111_controls),
+ .get_control = mt9m111_get_control,
+ .set_control = mt9m111_set_control,
+ .get_chip_id = mt9m111_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .get_register = mt9m111_get_register,
+ .set_register = mt9m111_set_register,
+#endif
+};
+
+static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret;
+
+ if (mt9m111->context == HIGHPOWER) {
+ if (flip)
+ ret = reg_set(READ_MODE_B, mask);
+ else
+ ret = reg_clear(READ_MODE_B, mask);
+ } else {
+ if (flip)
+ ret = reg_set(READ_MODE_A, mask);
+ else
+ ret = reg_clear(READ_MODE_A, mask);
+ }
+
+ return ret;
+}
+
+static int mt9m111_get_global_gain(struct soc_camera_device *icd)
+{
+ unsigned int data, gain;
+
+ data = reg_read(GLOBAL_GAIN);
+ if (data >= 0)
+ gain = ((data & (1 << 10)) * 2)
+ | ((data & (1 << 9)) * 2)
+ | (data & 0x2f);
+ else
+ gain = data;
+
+ return gain;
+}
+static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
+{
+ u16 val;
+
+ if (gain > 63 * 2 * 2)
+ return -EINVAL;
+
+ icd->gain = gain;
+ if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
+ val = (1 << 10) | (1 << 9) | (gain / 4);
+ else if ((gain >= 64) && (gain < 64 * 2))
+ val = (1 << 9) | (gain / 2);
+ else
+ val = gain;
+
+ return reg_write(GLOBAL_GAIN, val);
+}
+
+static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret;
+
+ if (on)
+ ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+ else
+ ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+
+ if (!ret)
+ mt9m111->autoexposure = on;
+
+ return ret;
+}
+static int mt9m111_get_control(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (mt9m111->context == HIGHPOWER)
+ data = reg_read(READ_MODE_B);
+ else
+ data = reg_read(READ_MODE_A);
+
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS);
+ break;
+ case V4L2_CID_HFLIP:
+ if (mt9m111->context == HIGHPOWER)
+ data = reg_read(READ_MODE_B);
+ else
+ data = reg_read(READ_MODE_A);
+
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
+ break;
+ case V4L2_CID_GAIN:
+ data = mt9m111_get_global_gain(icd);
+ if (data < 0)
+ return data;
+ ctrl->value = data;
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = mt9m111->autoexposure;
+ break;
+ }
+ return 0;
+}
+
+static int mt9m111_set_control(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ const struct v4l2_queryctrl *qctrl;
+ int ret;
+
+ qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
+
+ if (!qctrl)
+ return -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ mt9m111->vflip = ctrl->value;
+ ret = mt9m111_set_flip(icd, ctrl->value,
+ MT9M111_RMB_MIRROR_ROWS);
+ break;
+ case V4L2_CID_HFLIP:
+ mt9m111->hflip = ctrl->value;
+ ret = mt9m111_set_flip(icd, ctrl->value,
+ MT9M111_RMB_MIRROR_COLS);
+ break;
+ case V4L2_CID_GAIN:
+ ret = mt9m111_set_global_gain(icd, ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ret = mt9m111_set_autoexposure(icd, ctrl->value);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int mt9m111_restore_state(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+ mt9m111_set_context(icd, mt9m111->context);
+ mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
+ mt9m111_setup_rect(icd);
+ mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+ mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+ mt9m111_set_global_gain(icd, icd->gain);
+ mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+ return 0;
+}
+
+static int mt9m111_resume(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret = 0;
+
+ if (mt9m111->powered) {
+ ret = mt9m111_enable(icd);
+ if (!ret)
+ ret = mt9m111_reset(icd);
+ if (!ret)
+ ret = mt9m111_restore_state(icd);
+ }
+ return ret;
+}
+
+static int mt9m111_init(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret;
+
+ mt9m111->context = HIGHPOWER;
+ ret = mt9m111_enable(icd);
+ if (!ret)
+ ret = mt9m111_reset(icd);
+ if (!ret)
+ ret = mt9m111_set_context(icd, mt9m111->context);
+ if (!ret)
+ ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+ if (ret)
+ dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret);
+ return ret;
+}
+
+static int mt9m111_release(struct soc_camera_device *icd)
+{
+ int ret;
+
+ ret = mt9m111_disable(icd);
+ if (ret < 0)
+ dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret);
+
+ return ret;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m111_video_probe(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ s32 data;
+ int ret;
+
+ /*
+ * We must have a parent by now. And it cannot be a wrong one.
+ * So this entire test is completely redundant.
+ */
+ if (!icd->dev.parent ||
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+ return -ENODEV;
+
+ ret = mt9m111_enable(icd);
+ if (ret)
+ goto ei2c;
+ ret = mt9m111_reset(icd);
+ if (ret)
+ goto ei2c;
+
+ data = reg_read(CHIP_VERSION);
+
+ switch (data) {
+ case 0x143a:
+ mt9m111->model = V4L2_IDENT_MT9M111;
+ icd->formats = mt9m111_colour_formats;
+ icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
+ break;
+ default:
+ ret = -ENODEV;
+ dev_err(&icd->dev,
+ "No MT9M111 chip detected, register read %x\n", data);
+ goto ei2c;
+ }
+
+ dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n");
+
+ ret = soc_camera_video_start(icd);
+ if (ret)
+ goto eisis;
+
+ mt9m111->autoexposure = 1;
+
+ mt9m111->swap_rgb_even_odd = 1;
+ mt9m111->swap_rgb_red_blue = 1;
+
+ return 0;
+eisis:
+ei2c:
+ return ret;
+}
+
+static void mt9m111_video_remove(struct soc_camera_device *icd)
+{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+ dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr,
+ mt9m111->icd.dev.parent, mt9m111->icd.vdev);
+ soc_camera_video_stop(&mt9m111->icd);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+static int mt9m111_probe(struct i2c_client *client)
+#else
+static int mt9m111_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+#endif
+{
+ struct mt9m111 *mt9m111;
+ struct soc_camera_device *icd;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = client->dev.platform_data;
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "MT9M111 driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
+ if (!mt9m111)
+ return -ENOMEM;
+
+ mt9m111->client = client;
+ i2c_set_clientdata(client, mt9m111);
+
+ /* Second stage probe - when a capture adapter is there */
+ icd = &mt9m111->icd;
+ icd->ops = &mt9m111_ops;
+ icd->control = &client->dev;
+ icd->x_min = MT9M111_MIN_DARK_COLS;
+ icd->y_min = MT9M111_MIN_DARK_ROWS;
+ icd->x_current = icd->x_min;
+ icd->y_current = icd->y_min;
+ icd->width_min = MT9M111_MIN_DARK_ROWS;
+ icd->width_max = MT9M111_MAX_WIDTH;
+ icd->height_min = MT9M111_MIN_DARK_COLS;
+ icd->height_max = MT9M111_MAX_HEIGHT;
+ icd->y_skip_top = 0;
+ icd->iface = icl->bus_id;
+
+ ret = soc_camera_device_register(icd);
+ if (ret)
+ goto eisdr;
+ return 0;
+
+eisdr:
+ kfree(mt9m111);
+ return ret;
+}
+
+static int mt9m111_remove(struct i2c_client *client)
+{
+ struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
+ soc_camera_device_unregister(&mt9m111->icd);
+ kfree(mt9m111);
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id mt9m111_id[] = {
+ { "mt9m111", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m111_id);
+#endif
+
+static struct i2c_driver mt9m111_i2c_driver = {
+ .driver = {
+ .name = "mt9m111",
+ },
+ .probe = mt9m111_probe,
+ .remove = mt9m111_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = mt9m111_id,
+#endif
+};
+
+static int __init mt9m111_mod_init(void)
+{
+ return i2c_add_driver(&mt9m111_i2c_driver);
+}
+
+static void __exit mt9m111_mod_exit(void)
+{
+ i2c_del_driver(&mt9m111_i2c_driver);
+}
+
+module_init(mt9m111_mod_init);
+module_exit(mt9m111_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9M111 Camera driver");
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index 1ff36edd7..0320d006f 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -134,34 +134,56 @@ static int reg_clear(struct soc_camera_device *icd, const u8 reg,
static int mt9v022_init(struct soc_camera_device *icd)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
int ret;
+ if (icl->power) {
+ ret = icl->power(&mt9v022->client->dev, 1);
+ if (ret < 0) {
+ dev_err(icd->vdev->parent,
+ "Platform failed to power-on the camera.\n");
+ return ret;
+ }
+ }
+
+ /*
+ * The camera could have been already on, we hard-reset it additionally,
+ * if available. Soft reset is done in video_probe().
+ */
+ if (icl->reset)
+ icl->reset(&mt9v022->client->dev);
+
/* Almost the default mode: master, parallel, simultaneous, and an
* undocumented bit 0x200, which is present in table 7, but not in 8,
* plus snapshot mode to disable scan for now */
mt9v022->chip_control |= 0x10;
ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
- if (ret >= 0)
- reg_write(icd, MT9V022_READ_MODE, 0x300);
+ if (!ret)
+ ret = reg_write(icd, MT9V022_READ_MODE, 0x300);
/* All defaults */
- if (ret >= 0)
+ if (!ret)
/* AEC, AGC on */
ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
- if (ret >= 0)
+ if (!ret)
/* default - auto */
ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0);
- return ret >= 0 ? 0 : -EIO;
+ return ret;
}
static int mt9v022_release(struct soc_camera_device *icd)
{
- /* Nothing? */
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+
+ if (icl->power)
+ icl->power(&mt9v022->client->dev, 0);
+
return 0;
}
@@ -352,21 +374,21 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
rect->height + icd->y_skip_top + 43);
}
/* Setup frame format: defaults apart from width and height */
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9V022_ROW_START, rect->top);
- if (ret >= 0)
+ if (!ret)
/* Default 94, Phytec driver says:
* "width + horizontal blank >= 660" */
ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING,
rect->width > 660 - 43 ? 43 :
660 - rect->width);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width);
- if (ret >= 0)
+ if (!ret)
ret = reg_write(icd, MT9V022_WINDOW_HEIGHT,
rect->height + icd->y_skip_top);
@@ -717,7 +739,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
icd->num_formats = 1;
}
- if (ret >= 0)
+ if (!ret)
ret = soc_camera_video_start(icd);
if (ret < 0)
goto eisis;
diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c
index bf2462a58..e0fbbd3a7 100644
--- a/linux/drivers/media/video/mxb.c
+++ b/linux/drivers/media/video/mxb.c
@@ -467,15 +467,15 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
/* checking for i2c-devices can be omitted here, because we
already did this in "mxb_vl42_probe" */
- saa7146_vv_init(dev,&vv_data);
- if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
+ saa7146_vv_init(dev, &vv_data);
+ if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
}
/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
- if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
- if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
+ if (MXB_BOARD_CAN_DO_VBI(dev)) {
+ if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
ERR(("cannot register vbi v4l2 device. skipping.\n"));
}
}
@@ -487,7 +487,7 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
i2c_use_client(mxb->saa7111a);
i2c_use_client(mxb->tuner);
- printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
+ printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
mxb_num++;
mxb_init_done(dev);
@@ -738,8 +738,8 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
memset(t,0,sizeof(*t));
- strcpy(t->name, "Television");
+ strlcpy(t->name, "Television", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
@@ -747,7 +747,6 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
/* FIXME: add the real signal strength here */
t->signal = 0xffff;
t->afc = 0;
-
mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
t->audmode = mxb->cur_mode;
@@ -932,27 +931,29 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
{
- struct mxb* mxb = (struct mxb*)dev->ext_priv;
+ struct mxb *mxb = (struct mxb *)dev->ext_priv;
int zero = 0;
int one = 1;
- if(V4L2_STD_PAL_I == std->id ) {
+ if (V4L2_STD_PAL_I == standard->id) {
v4l2_std_id std = V4L2_STD_PAL_I;
+
DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* unset the 7111 gpio register -- I don't know what this does exactly */
- mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
+ mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
} else {
v4l2_std_id std = V4L2_STD_PAL_BG;
+
DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* set the 7111 gpio register -- I don't know what this does exactly */
- mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
+ mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
}
return 0;
diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c
index c693b6fb0..1c5b07566 100644
--- a/linux/drivers/media/video/ov511.c
+++ b/linux/drivers/media/video/ov511.c
@@ -626,9 +626,9 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
break;
/* Retry until idle */
- do
+ do {
rc = reg_r(ov, R511_I2C_CTL);
- while (rc > 0 && ((rc&1) == 0));
+ } while (rc > 0 && ((rc&1) == 0));
if (rc < 0)
break;
@@ -703,9 +703,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
return rc;
/* Retry until idle */
- do
- rc = reg_r(ov, R511_I2C_CTL);
- while (rc > 0 && ((rc&1) == 0));
+ do {
+ rc = reg_r(ov, R511_I2C_CTL);
+ } while (rc > 0 && ((rc & 1) == 0));
if (rc < 0)
return rc;
@@ -729,9 +729,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
return rc;
/* Retry until idle */
- do
+ do {
rc = reg_r(ov, R511_I2C_CTL);
- while (rc > 0 && ((rc&1) == 0));
+ } while (rc > 0 && ((rc&1) == 0));
if (rc < 0)
return rc;
diff --git a/linux/drivers/media/video/pms.c b/linux/drivers/media/video/pms.c
index e36b39b44..8c51ee442 100644
--- a/linux/drivers/media/video/pms.c
+++ b/linux/drivers/media/video/pms.c
@@ -1020,10 +1020,23 @@ static int init_mediavision(void)
* Initialization and module stuff
*/
+#ifndef MODULE
+static int enable;
+module_param(enable, int, 0);
+#endif
+
static int __init init_pms_cards(void)
{
printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
+#ifndef MODULE
+ if (!enable) {
+ printk(KERN_INFO "PMS: not enabled, use pms.enable=1 to "
+ "probe\n");
+ return -ENODEV;
+ }
+#endif
+
data_port = io_port +1;
if(init_mediavision())
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 419a473cf..881610b60 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -1324,8 +1324,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
/* Usbsnoop log shows that we must swap bytes... */
for (icnt = 0; icnt < bcnt/4 ; icnt++)
- ((u32 *)fw_ptr)[icnt] =
- ___swab32(((u32 *)fw_ptr)[icnt]);
+ ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]);
ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
&actual_length, HZ);
diff --git a/linux/drivers/media/video/pwc/pwc-ctrl.c b/linux/drivers/media/video/pwc/pwc-ctrl.c
index 1cccd5c77..dbc560742 100644
--- a/linux/drivers/media/video/pwc/pwc-ctrl.c
+++ b/linux/drivers/media/video/pwc/pwc-ctrl.c
@@ -1635,15 +1635,15 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
case VIDIOCPWCGVIDCMD:
{
- ARG_DEF(struct pwc_video_command, cmd);
-
- ARGR(cmd).type = pdev->type;
- ARGR(cmd).release = pdev->release;
- ARGR(cmd).command_len = pdev->cmd_len;
- memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
- ARGR(cmd).bandlength = pdev->vbandlength;
- ARGR(cmd).frame_size = pdev->frame_size;
- ARG_OUT(cmd)
+ ARG_DEF(struct pwc_video_command, vcmd);
+
+ ARGR(vcmd).type = pdev->type;
+ ARGR(vcmd).release = pdev->release;
+ ARGR(vcmd).command_len = pdev->cmd_len;
+ memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+ ARGR(vcmd).bandlength = pdev->vbandlength;
+ ARGR(vcmd).frame_size = pdev->frame_size;
+ ARG_OUT(vcmd)
break;
}
/*
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index ead87ddaf..ee2fb7baa 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -36,8 +36,13 @@
#include <linux/videodev2.h>
#include <asm/dma.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+#include <mach/pxa-regs.h>
+#include <mach/camera.h>
+#else
#include <asm/arch/pxa-regs.h>
#include <asm/arch/camera.h>
+#endif
#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
#define PXA_CAM_DRV_NAME "pxa27x-camera"
@@ -629,17 +634,6 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
pdata->init(pcdev->dev);
}
- if (pdata && pdata->power) {
- dev_dbg(pcdev->dev, "%s: Power on camera\n", __func__);
- pdata->power(pcdev->dev, 1);
- }
-
- if (pdata && pdata->reset) {
- dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
- __func__);
- pdata->reset(pcdev->dev, 1);
- }
-
CICR0 = 0x3FF; /* disable all interrupts */
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
@@ -660,20 +654,7 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
{
- struct pxacamera_platform_data *board = pcdev->pdata;
-
clk_disable(pcdev->clk);
-
- if (board && board->reset) {
- dev_dbg(pcdev->dev, "%s: Asserting camera reset\n",
- __func__);
- board->reset(pcdev->dev, 0);
- }
-
- if (board && board->power) {
- dev_dbg(pcdev->dev, "%s: Power off camera\n", __func__);
- board->power(pcdev->dev, 0);
- }
}
static irqreturn_t pxa_camera_irq(int irq, void *data)
diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c
index 939edff48..c5a6dd115 100644
--- a/linux/drivers/media/video/s2255drv.c
+++ b/linux/drivers/media/video/s2255drv.c
@@ -68,20 +68,21 @@
/* USB endpoint number for configuring the device */
#define S2255_CONFIG_EP 2
/* maximum time for DSP to start responding after last FW word loaded(ms) */
-#define S2255_DSP_BOOTTIME 400
+#define S2255_DSP_BOOTTIME 800
/* maximum time to wait for firmware to load (ms) */
#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME)
#define S2255_DEF_BUFS 16
+#define S2255_SETMODE_TIMEOUT 500
#define MAX_CHANNELS 4
-#define FRAME_MARKER 0x2255DA4AL
-#define MAX_PIPE_USBBLOCK (40 * 1024)
-#define DEFAULT_PIPE_USBBLOCK (16 * 1024)
+#define S2255_MARKER_FRAME 0x2255DA4AL
+#define S2255_MARKER_RESPONSE 0x2255ACACL
+#define S2255_USB_XFER_SIZE (16 * 1024)
#define MAX_CHANNELS 4
#define MAX_PIPE_BUFFERS 1
#define SYS_FRAMES 4
/* maximum size is PAL full size plus room for the marker header(s) */
-#define SYS_FRAMES_MAXSIZE (720 * 288 * 2 * 2 + 4096)
-#define DEF_USB_BLOCK (4096)
+#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096)
+#define DEF_USB_BLOCK S2255_USB_XFER_SIZE
#define LINE_SZ_4CIFS_NTSC 640
#define LINE_SZ_2CIFS_NTSC 640
#define LINE_SZ_1CIFS_NTSC 320
@@ -109,6 +110,9 @@
#define COLOR_YUVPL 1 /* YUV planar */
#define COLOR_YUVPK 2 /* YUV packed */
#define COLOR_Y8 4 /* monochrome */
+#define COLOR_JPG 5 /* JPEG */
+#define MASK_COLOR 0xff
+#define MASK_JPG_QUALITY 0xff00
/* frame decimation. Not implemented by V4L yet(experimental in V4L) */
#define FDEC_1 1 /* capture every frame. default */
@@ -149,16 +153,14 @@ struct s2255_mode {
u32 restart; /* if DSP requires restart */
};
-/* frame structure */
-#define FRAME_STATE_UNUSED 0
-#define FRAME_STATE_FILLING 1
-#define FRAME_STATE_FULL 2
+#define S2255_READ_IDLE 0
+#define S2255_READ_FRAME 1
+/* frame structure */
struct s2255_framei {
unsigned long size;
-
- unsigned long ulState; /* ulState ==0 unused, 1 being filled, 2 full */
+ unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/
void *lpvbits; /* image data */
unsigned long cur_size; /* current data copied to it */
};
@@ -189,6 +191,10 @@ struct s2255_dmaqueue {
#define S2255_FW_FAILED 3
#define S2255_FW_DISCONNECTING 4
+#define S2255_FW_MARKER 0x22552f2f
+/* 2255 read states */
+#define S2255_READ_IDLE 0
+#define S2255_READ_FRAME 1
struct s2255_fw {
int fw_loaded;
int fw_size;
@@ -196,7 +202,6 @@ struct s2255_fw {
atomic_t fw_state;
void *pfw_data;
wait_queue_head_t wait_fw;
- struct timer_list dsp_wait;
const struct firmware *fw;
};
@@ -243,10 +248,20 @@ struct s2255_dev {
int last_frame[MAX_CHANNELS];
u32 cc; /* current channel */
int b_acquire[MAX_CHANNELS];
+ /* allocated image size */
unsigned long req_image_size[MAX_CHANNELS];
+ /* received packet size */
+ unsigned long pkt_size[MAX_CHANNELS];
int bad_payload[MAX_CHANNELS];
unsigned long frame_count[MAX_CHANNELS];
int frame_ready;
+ /* if JPEG image */
+ int jpg_size[MAX_CHANNELS];
+ /* if channel configured to default state */
+ int chn_configured[MAX_CHANNELS];
+ wait_queue_head_t wait_setmode[MAX_CHANNELS];
+ int setmode_ready[MAX_CHANNELS];
+ int chn_ready;
struct kref kref;
spinlock_t slock;
};
@@ -307,12 +322,16 @@ static void s2255_stop_readpipe(struct s2255_dev *dev);
static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
- int chn);
+ int chn, int jpgsize);
static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
struct s2255_mode *mode);
static int s2255_board_shutdown(struct s2255_dev *dev);
static void s2255_exit_v4l(struct s2255_dev *dev);
-static void s2255_fwload_start(struct s2255_dev *dev);
+static void s2255_fwload_start(struct s2255_dev *dev, int reset);
+static void s2255_destroy(struct kref *kref);
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
+ u16 index, u16 value, void *buf,
+ s32 buf_len, int bOut);
#define dprintk(level, fmt, arg...) \
do { \
@@ -408,6 +427,10 @@ static const struct s2255_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16
}, {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }, {
.name = "8bpp GREY",
.fourcc = V4L2_PIX_FMT_GREY,
.depth = 8
@@ -465,6 +488,13 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
return;
}
+void s2255_reset_dsppower(struct s2255_dev *dev)
+{
+ s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b0b, NULL, 0, 1);
+ msleep(10);
+ s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
+ return;
+}
/* kickstarts the firmware loading. from probe
*/
@@ -481,18 +511,6 @@ static void s2255_timer(unsigned long user_data)
}
}
-/* called when DSP is up and running. DSP is guaranteed to
- be running after S2255_DSP_BOOTTIME */
-static void s2255_dsp_running(unsigned long user_data)
-{
- struct s2255_fw *data = (struct s2255_fw *)user_data;
- dprintk(1, "dsp running\n");
- atomic_set(&data->fw_state, S2255_FW_SUCCESS);
- wake_up(&data->wait_fw);
- printk(KERN_INFO "s2255: firmware loaded successfully\n");
- return;
-}
-
/* this loads the firmware asynchronously.
Originally this was done synchroously in probe.
@@ -550,19 +568,14 @@ static void s2255_fwchunk_complete(struct urb *urb)
}
data->fw_loaded += len;
} else {
- init_timer(&data->dsp_wait);
- data->dsp_wait.function = s2255_dsp_running;
- data->dsp_wait.data = (unsigned long)data;
atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
- mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME)
- + jiffies);
}
dprintk(100, "2255 complete done\n");
return;
}
-static int s2255_got_frame(struct s2255_dev *dev, int chn)
+static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
{
struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
struct s2255_buffer *buf;
@@ -587,8 +600,7 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn)
list_del(&buf->vb.queue);
do_gettimeofday(&buf->vb.ts);
dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
-
- s2255_fillbuff(dev, buf, dma_q->channel);
+ s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
wake_up(&buf->vb.done);
dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
unlock:
@@ -622,7 +634,7 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
*
*/
static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
- int chn)
+ int chn, int jpgsize)
{
int pos = 0;
struct timeval ts;
@@ -650,6 +662,10 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
case V4L2_PIX_FMT_GREY:
memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
break;
+ case V4L2_PIX_FMT_JPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
case V4L2_PIX_FMT_YUV422P:
memcpy(vbuf, tmpbuf,
buf->vb.width * buf->vb.height * 2);
@@ -658,9 +674,6 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
printk(KERN_DEBUG "s2255: unknown format?\n");
}
dev->last_frame[chn] = -1;
- /* done with the frame, free it */
- frm->ulState = 0;
- dprintk(4, "freeing buffer\n");
} else {
printk(KERN_ERR "s2255: =======no frame\n");
return;
@@ -1022,6 +1035,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
case V4L2_PIX_FMT_GREY:
fh->mode.color = COLOR_Y8;
break;
+ case V4L2_PIX_FMT_JPEG:
+ fh->mode.color = COLOR_JPG | (50 << 8);
+ break;
case V4L2_PIX_FMT_YUV422P:
fh->mode.color = COLOR_YUVPL;
break;
@@ -1140,7 +1156,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
}
}
outImageSize = linesPerFrame * pixelsPerLine;
- if (mode->color != COLOR_Y8) {
+ if ((mode->color & MASK_COLOR) != COLOR_Y8) {
/* 2 bytes/pixel if not monochrome */
outImageSize *= 2;
}
@@ -1186,6 +1202,7 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
u32 *buffer;
unsigned long chn_rev;
+ mutex_lock(&dev->lock);
chn_rev = G_chnmap[chn];
dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale);
dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn],
@@ -1200,6 +1217,7 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
+ mutex_unlock(&dev->lock);
return -ENOMEM;
}
@@ -1215,12 +1233,20 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
dprintk(1, "set mode done chn %lu, %d\n", chn, res);
/* wait at least 3 frames before continuing */
- if (mode->restart)
- msleep(125);
+ if (mode->restart) {
+ dev->setmode_ready[chn] = 0;
+ wait_event_timeout(dev->wait_setmode[chn],
+ (dev->setmode_ready[chn] != 0),
+ msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
+ if (dev->setmode_ready[chn] != 1) {
+ printk(KERN_DEBUG "s2255: no set mode response\n");
+ res = -EFAULT;
+ }
+ }
/* clear the restart flag */
dev->mode[chn].restart = 0;
-
+ mutex_unlock(&dev->lock);
return res;
}
@@ -1270,7 +1296,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
dev->bad_payload[chn] = 0;
dev->cur_frame[chn] = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- dev->buffer[chn].frame[j].ulState = 0;
+ dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
dev->buffer[chn].frame[j].cur_size = 0;
}
res = videobuf_streamon(&fh->vb_vidq);
@@ -1455,6 +1481,7 @@ static int s2255_open(struct inode *inode, struct file *file)
enum v4l2_buf_type type = 0;
int i = 0;
int cur_channel = -1;
+ int state;
dprintk(1, "s2255: open called (minor=%d)\n", minor);
lock_kernel();
@@ -1471,47 +1498,77 @@ static int s2255_open(struct inode *inode, struct file *file)
if ((NULL == dev) || (cur_channel == -1)) {
unlock_kernel();
- dprintk(1, "s2255: openv4l no dev\n");
+ printk(KERN_INFO "s2255: openv4l no dev\n");
return -ENODEV;
}
+ if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) {
+ unlock_kernel();
+ printk(KERN_INFO "disconnecting\n");
+ return -ENODEV;
+ }
+ kref_get(&dev->kref);
mutex_lock(&dev->open_lock);
dev->users[cur_channel]++;
dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]);
- if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) {
+ switch (atomic_read(&dev->fw_data->fw_state)) {
+ case S2255_FW_FAILED:
err("2255 firmware load failed. retrying.\n");
- s2255_fwload_start(dev);
+ s2255_fwload_start(dev, 1);
wait_event_timeout(dev->fw_data->wait_fw,
- (atomic_read(&dev->fw_data->fw_state)
- != S2255_FW_NOTLOADED),
+ ((atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_SUCCESS) ||
+ (atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_DISCONNECTING)),
msecs_to_jiffies(S2255_LOAD_TIMEOUT));
- if (atomic_read(&dev->fw_data->fw_state)
- != S2255_FW_SUCCESS) {
- printk(KERN_INFO "2255 FW load failed.\n");
- dev->users[cur_channel]--;
- mutex_unlock(&dev->open_lock);
- unlock_kernel();
- return -EFAULT;
- }
- } else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) {
+ break;
+ case S2255_FW_NOTLOADED:
+ case S2255_FW_LOADED_DSPWAIT:
/* give S2255_LOAD_TIMEOUT time for firmware to load in case
driver loaded and then device immediately opened */
printk(KERN_INFO "%s waiting for firmware load\n", __func__);
wait_event_timeout(dev->fw_data->wait_fw,
- (atomic_read(&dev->fw_data->fw_state)
- != S2255_FW_NOTLOADED),
- msecs_to_jiffies(S2255_LOAD_TIMEOUT));
- if (atomic_read(&dev->fw_data->fw_state)
- != S2255_FW_SUCCESS) {
- printk(KERN_INFO "2255 firmware not loaded"
- "try again\n");
- dev->users[cur_channel]--;
- mutex_unlock(&dev->open_lock);
- unlock_kernel();
- return -EBUSY;
+ ((atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_SUCCESS) ||
+ (atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_DISCONNECTING)),
+ msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+ break;
+ case S2255_FW_SUCCESS:
+ default:
+ break;
+ }
+ state = atomic_read(&dev->fw_data->fw_state);
+ if (state != S2255_FW_SUCCESS) {
+ int rc;
+ switch (state) {
+ case S2255_FW_FAILED:
+ printk(KERN_INFO "2255 FW load failed. %d\n", state);
+ rc = -ENODEV;
+ break;
+ case S2255_FW_DISCONNECTING:
+ printk(KERN_INFO "%s: disconnecting\n", __func__);
+ rc = -ENODEV;
+ break;
+ case S2255_FW_LOADED_DSPWAIT:
+ case S2255_FW_NOTLOADED:
+ printk(KERN_INFO "%s: firmware not loaded yet"
+ "please try again later\n",
+ __func__);
+ rc = -EAGAIN;
+ break;
+ default:
+ printk(KERN_INFO "%s: unknown state\n", __func__);
+ rc = -EFAULT;
+ break;
}
+ dev->users[cur_channel]--;
+ mutex_unlock(&dev->open_lock);
+ kref_put(&dev->kref, s2255_destroy);
+ unlock_kernel();
+ return rc;
}
/* allocate + initialize per filehandle data */
@@ -1519,6 +1576,7 @@ static int s2255_open(struct inode *inode, struct file *file)
if (NULL == fh) {
dev->users[cur_channel]--;
mutex_unlock(&dev->open_lock);
+ kref_put(&dev->kref, s2255_destroy);
unlock_kernel();
return -ENOMEM;
}
@@ -1533,6 +1591,13 @@ static int s2255_open(struct inode *inode, struct file *file)
fh->height = NUM_LINES_4CIFS_NTSC * 2;
fh->channel = cur_channel;
+ /* configure channel to default state */
+ if (!dev->chn_configured[cur_channel]) {
+ s2255_set_mode(dev, cur_channel, &fh->mode);
+ dev->chn_configured[cur_channel] = 1;
+ }
+
+
/* Put all controls at a sane state */
for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
qctl_regs[i] = s2255_qctrl[i].default_value;
@@ -1551,7 +1616,6 @@ static int s2255_open(struct inode *inode, struct file *file)
V4L2_FIELD_INTERLACED,
sizeof(struct s2255_buffer), fh);
- kref_get(&dev->kref);
mutex_unlock(&dev->open_lock);
unlock_kernel();
return 0;
@@ -1575,30 +1639,24 @@ static unsigned int s2255_poll(struct file *file,
static void s2255_destroy(struct kref *kref)
{
struct s2255_dev *dev = to_s2255_dev(kref);
+ struct list_head *list;
+ int i;
if (!dev) {
printk(KERN_ERR "s2255drv: kref problem\n");
return;
}
-
- /*
- * Wake up any firmware load waiting (only done in .open,
- * which holds the open_lock mutex)
- */
atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
wake_up(&dev->fw_data->wait_fw);
-
- /* prevent s2255_disconnect from racing s2255_open */
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ dev->setmode_ready[i] = 1;
+ wake_up(&dev->wait_setmode[i]);
+ }
mutex_lock(&dev->open_lock);
+ /* reset the DSP so firmware can be reload next time */
+ s2255_reset_dsppower(dev);
s2255_exit_v4l(dev);
- /*
- * device unregistered so no longer possible to open. open_mutex
- * can be unlocked and timers deleted afterwards.
- */
- mutex_unlock(&dev->open_lock);
-
/* board shutdown stops the read pipe if it is running */
s2255_board_shutdown(dev);
-
/* make sure firmware still not trying to load */
del_timer(&dev->timer); /* only started in .probe and .open */
@@ -1608,23 +1666,19 @@ static void s2255_destroy(struct kref *kref)
usb_free_urb(dev->fw_data->fw_urb);
dev->fw_data->fw_urb = NULL;
}
-
- /*
- * delete the dsp_wait timer, which sets the firmware
- * state on completion. This is done before fw_data
- * is freed below.
- */
-
- del_timer(&dev->fw_data->dsp_wait); /* only started in .open */
-
if (dev->fw_data->fw)
release_firmware(dev->fw_data->fw);
kfree(dev->fw_data->pfw_data);
kfree(dev->fw_data);
-
usb_put_dev(dev->udev);
dprintk(1, "%s", __func__);
kfree(dev);
+
+ while (!list_empty(&s2255_devlist)) {
+ list = s2255_devlist.next;
+ list_del(list);
+ }
+ mutex_unlock(&dev->open_lock);
}
static int s2255_close(struct inode *inode, struct file *file)
@@ -1760,18 +1814,16 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
static void s2255_exit_v4l(struct s2255_dev *dev)
{
- struct list_head *list;
+
int i;
- /* unregister the video devices */
- while (!list_empty(&s2255_devlist)) {
- list = s2255_devlist.next;
- list_del(list);
- }
for (i = 0; i < MAX_CHANNELS; i++) {
- if (-1 != dev->vdev[i]->minor)
+ if (-1 != dev->vdev[i]->minor) {
video_unregister_device(dev->vdev[i]);
- else
+ printk(KERN_INFO "s2255 unregistered\n");
+ } else {
video_device_release(dev->vdev[i]);
+ printk(KERN_INFO "s2255 released\n");
+ }
}
}
@@ -1781,134 +1833,123 @@ static void s2255_exit_v4l(struct s2255_dev *dev)
* function again).
*
* Received frame structure:
- * bytes 0-3: marker : 0x2255DA4AL (FRAME_MARKER)
+ * bytes 0-3: marker : 0x2255DA4AL (S2255_MARKER_FRAME)
* bytes 4-7: channel: 0-3
* bytes 8-11: payload size: size of the frame
* bytes 12-payloadsize+12: frame data
*/
static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
{
- static int dbgsync; /* = 0; */
char *pdest;
u32 offset = 0;
- int bsync = 0;
- int btrunc = 0;
+ int bframe = 0;
char *psrc;
unsigned long copy_size;
unsigned long size;
s32 idx = -1;
struct s2255_framei *frm;
unsigned char *pdata;
- unsigned long cur_size;
- int bsearch = 0;
- struct s2255_bufferi *buf;
+
dprintk(100, "buffer to user\n");
idx = dev->cur_frame[dev->cc];
- buf = &dev->buffer[dev->cc];
- frm = &buf->frame[idx];
-
- if (frm->ulState == 0) {
- frm->ulState = 1;
- frm->cur_size = 0;
- bsearch = 1;
- } else if (frm->ulState == 2) {
- /* system frame was not freed */
- dprintk(2, "sys frame not free. overrun ringbuf\n");
- bsearch = 1;
- frm->ulState = 1;
- frm->cur_size = 0;
- }
-
- if (bsearch) {
- if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) {
- u32 jj;
- if (dbgsync == 0) {
- dprintk(3, "not synched, discarding all packets"
- "until marker\n");
+ frm = &dev->buffer[dev->cc].frame[idx];
- dbgsync++;
- }
- pdata = (unsigned char *)pipe_info->transfer_buffer;
- for (jj = 0; jj < (pipe_info->cur_transfer_size - 12);
- jj++) {
- if (*(s32 *) pdata == FRAME_MARKER) {
- int cc;
- dprintk(3,
- "found frame marker at offset:"
- " %d [%x %x]\n", jj, pdata[0],
- pdata[1]);
- offset = jj;
- bsync = 1;
- cc = *(u32 *) (pdata + sizeof(u32));
- if (cc >= MAX_CHANNELS) {
- printk(KERN_ERR
- "bad channel\n");
- return -EINVAL;
- }
- /* reverse it */
- dev->cc = G_chnmap[cc];
+ if (frm->ulState == S2255_READ_IDLE) {
+ int jj;
+ unsigned int cc;
+ s32 *pdword;
+ int payload;
+ /* search for marker codes */
+ pdata = (unsigned char *)pipe_info->transfer_buffer;
+ for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
+ switch (*(s32 *) pdata) {
+ case S2255_MARKER_FRAME:
+ pdword = (s32 *)pdata;
+ dprintk(4, "found frame marker at offset:"
+ " %d [%x %x]\n", jj, pdata[0],
+ pdata[1]);
+ offset = jj + PREFIX_SIZE;
+ bframe = 1;
+ cc = pdword[1];
+ if (cc >= MAX_CHANNELS) {
+ printk(KERN_ERR
+ "bad channel\n");
+ return -EINVAL;
+ }
+ /* reverse it */
+ dev->cc = G_chnmap[cc];
+ payload = pdword[3];
+ if (payload > dev->req_image_size[dev->cc]) {
+ dev->bad_payload[dev->cc]++;
+ /* discard the bad frame */
+ return -EINVAL;
+ }
+ dev->pkt_size[dev->cc] = payload;
+ dev->jpg_size[dev->cc] = pdword[4];
+ break;
+ case S2255_MARKER_RESPONSE:
+ pdword = (s32 *)pdata;
+ pdata += DEF_USB_BLOCK;
+ jj += DEF_USB_BLOCK;
+ if (pdword[1] >= MAX_CHANNELS)
+ break;
+ cc = G_chnmap[pdword[1]];
+ if (!(cc >= 0 && cc < MAX_CHANNELS))
+ break;
+ switch (pdword[2]) {
+ case 0x01:
+ /* check if channel valid */
+ /* set mode ready */
+ dev->setmode_ready[cc] = 1;
+ wake_up(&dev->wait_setmode[cc]);
+ dprintk(5, "setmode ready %d\n", cc);
break;
+ case 0x10:
+
+ dev->chn_ready |= (1 << cc);
+ if ((dev->chn_ready & 0x0f) != 0x0f)
+ break;
+ /* all channels ready */
+ printk(KERN_INFO "s2255: fw loaded\n");
+ atomic_set(&dev->fw_data->fw_state,
+ S2255_FW_SUCCESS);
+ wake_up(&dev->fw_data->wait_fw);
+ break;
+ default:
+ printk(KERN_INFO "s2255 unknwn resp\n");
}
+ default:
pdata++;
+ break;
}
- if (bsync == 0)
- return -EINVAL;
- } else {
- u32 *pword;
- u32 payload;
- int cc;
- dbgsync = 0;
- bsync = 1;
- pword = (u32 *) pipe_info->transfer_buffer;
- cc = pword[1];
-
- if (cc >= MAX_CHANNELS) {
- printk("invalid channel found. "
- "throwing out data!\n");
- return -EINVAL;
- }
- dev->cc = G_chnmap[cc];
- payload = pword[2];
- if (payload != dev->req_image_size[dev->cc]) {
- dprintk(1, "[%d][%d]unexpected payload: %d"
- "required: %lu \n", cc, dev->cc,
- payload, dev->req_image_size[dev->cc]);
- dev->bad_payload[dev->cc]++;
- /* discard the bad frame */
- return -EINVAL;
- }
-
- }
- }
- /* search done. now find out if should be acquiring
- on this channel */
- if (!dev->b_acquire[dev->cc]) {
- frm->ulState = 0;
- return -EINVAL;
+ if (bframe)
+ break;
+ } /* for */
+ if (!bframe)
+ return -EINVAL;
}
+
idx = dev->cur_frame[dev->cc];
frm = &dev->buffer[dev->cc].frame[idx];
- if (frm->ulState == 0) {
- frm->ulState = 1;
- frm->cur_size = 0;
- } else if (frm->ulState == 2) {
- /* system frame ring buffer overrun */
- dprintk(2, "sys frame overrun. overwriting frame %d %d\n",
- dev->cc, idx);
- frm->ulState = 1;
- frm->cur_size = 0;
+ /* search done. now find out if should be acquiring on this channel */
+ if (!dev->b_acquire[dev->cc]) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = S2255_READ_IDLE;
+ return -EINVAL;
}
- if (bsync) {
- /* skip the marker 512 bytes (and offset if out of sync) */
- psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE;
- } else {
- psrc = (u8 *)pipe_info->transfer_buffer;
+ if (frm->ulState == S2255_READ_IDLE) {
+ frm->ulState = S2255_READ_FRAME;
+ frm->cur_size = 0;
}
+ /* skip the marker 512 bytes (and offset if out of sync) */
+ psrc = (u8 *)pipe_info->transfer_buffer + offset;
+
+
if (frm->lpvbits == NULL) {
dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
frm, dev, dev->cc, idx);
@@ -1917,33 +1958,20 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
pdest = frm->lpvbits + frm->cur_size;
- if (bsync) {
- copy_size =
- (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE;
- if (copy_size > pipe_info->cur_transfer_size) {
- printk("invalid copy size, overflow!\n");
- return -ENOMEM;
- }
- } else {
- copy_size = pipe_info->cur_transfer_size;
- }
+ copy_size = (pipe_info->cur_transfer_size - offset);
- cur_size = frm->cur_size;
- size = dev->req_image_size[dev->cc];
+ size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
- if ((copy_size + cur_size) > size) {
- copy_size = size - cur_size;
- btrunc = 1;
- }
+ /* sanity check on pdest */
+ if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+ memcpy(pdest, psrc, copy_size);
- memcpy(pdest, psrc, copy_size);
- cur_size += copy_size;
frm->cur_size += copy_size;
- dprintk(50, "cur_size size %lu size %lu \n", cur_size, size);
+ dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
+
+ if (frm->cur_size >= size) {
- if (cur_size >= (size - PREFIX_SIZE)) {
u32 cc = dev->cc;
- frm->ulState = 2;
dprintk(2, "****************[%d]Buffer[%d]full*************\n",
cc, idx);
dev->last_frame[cc] = dev->cur_frame[cc];
@@ -1952,16 +1980,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
if ((dev->cur_frame[cc] == SYS_FRAMES) ||
(dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
dev->cur_frame[cc] = 0;
-
- /* signal the semaphore for this channel */
+ /* frame ready */
if (dev->b_acquire[cc])
- s2255_got_frame(dev, cc);
+ s2255_got_frame(dev, cc, dev->jpg_size[cc]);
dev->frame_count[cc]++;
- }
- /* frame was truncated */
- if (btrunc) {
- /* return more data to process */
- return EAGAIN;
+ frm->ulState = S2255_READ_IDLE;
+ frm->cur_size = 0;
+
}
/* done successfully */
return 0;
@@ -1980,8 +2005,8 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
}
/* otherwise copy to the system buffers */
res = save_frame(dev, pipe_info);
- if (res == EAGAIN)
- save_frame(dev, pipe_info);
+ if (res != 0)
+ dprintk(4, "s2255: read callback failed\n");
dprintk(50, "callback read video done\n");
return;
@@ -2101,11 +2126,9 @@ static int s2255_board_init(struct s2255_dev *dev)
memset(pipe, 0, sizeof(*pipe));
pipe->dev = dev;
- pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK;
- pipe->max_transfer_size = MAX_PIPE_USBBLOCK;
+ pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
+ pipe->max_transfer_size = S2255_USB_XFER_SIZE;
- if (pipe->cur_transfer_size > pipe->max_transfer_size)
- pipe->cur_transfer_size = pipe->max_transfer_size;
pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
GFP_KERNEL);
if (pipe->transfer_buffer == NULL) {
@@ -2329,7 +2352,7 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
kfree(buffer);
dev->b_acquire[chn] = 0;
- return 0;
+ return res;
}
static void s2255_stop_readpipe(struct s2255_dev *dev)
@@ -2365,8 +2388,10 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
return;
}
-static void s2255_fwload_start(struct s2255_dev *dev)
+static void s2255_fwload_start(struct s2255_dev *dev, int reset)
{
+ if (reset)
+ s2255_reset_dsppower(dev);
dev->fw_data->fw_size = dev->fw_data->fw->size;
atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
memcpy(dev->fw_data->pfw_data,
@@ -2389,6 +2414,8 @@ static int s2255_probe(struct usb_interface *interface,
struct usb_endpoint_descriptor *endpoint;
int i;
int retval = -ENOMEM;
+ __le32 *pdata;
+ int fw_size;
dprintk(2, "s2255: probe\n");
@@ -2443,6 +2470,8 @@ static int s2255_probe(struct usb_interface *interface,
dev->timer.data = (unsigned long)dev->fw_data;
init_waitqueue_head(&dev->fw_data->wait_fw);
+ for (i = 0; i < MAX_CHANNELS; i++)
+ init_waitqueue_head(&dev->wait_setmode[i]);
dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2462,16 +2491,30 @@ static int s2255_probe(struct usb_interface *interface,
printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
goto error;
}
+ /* check the firmware is valid */
+ fw_size = dev->fw_data->fw->size;
+ pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
+ if (*pdata != S2255_FW_MARKER) {
+ printk(KERN_INFO "Firmware invalid.\n");
+ retval = -ENODEV;
+ goto error;
+ } else {
+ /* make sure firmware is the latest */
+ __le32 *pRel;
+ pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
+ printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
+ }
/* loads v4l specific */
s2255_probe_v4l(dev);
+ usb_reset_device(dev->udev);
/* load 2255 board specific */
s2255_board_init(dev);
dprintk(4, "before probe done %p\n", dev);
spin_lock_init(&dev->slock);
- s2255_fwload_start(dev);
+ s2255_fwload_start(dev, 0);
dev_info(&interface->dev, "Sensoray 2255 detected\n");
return 0;
error:
@@ -2482,14 +2525,30 @@ error:
static void s2255_disconnect(struct usb_interface *interface)
{
struct s2255_dev *dev = NULL;
+ int i;
dprintk(1, "s2255: disconnect interface %p\n", interface);
dev = usb_get_intfdata(interface);
+
+ /*
+ * wake up any of the timers to allow open_lock to be
+ * acquired sooner
+ */
+ atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
+ wake_up(&dev->fw_data->wait_fw);
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ dev->setmode_ready[i] = 1;
+ wake_up(&dev->wait_setmode[i]);
+ }
+
+ mutex_lock(&dev->open_lock);
+ usb_set_intfdata(interface, NULL);
+ mutex_unlock(&dev->open_lock);
+
if (dev) {
kref_put(&dev->kref, s2255_destroy);
dprintk(1, "s2255drv: disconnect\n");
dev_info(&interface->dev, "s2255usb now disconnected\n");
}
- usb_set_intfdata(interface, NULL);
}
static struct usb_driver s2255_driver = {
diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c
index c5c19a2e3..011fc19f6 100644
--- a/linux/drivers/media/video/saa7134/saa6752hs.c
+++ b/linux/drivers/media/video/saa7134/saa6752hs.c
@@ -1,3 +1,27 @@
+ /*
+ saa6752hs - i2c-driver for the saa6752hs by Philips
+
+ Copyright (C) 2004 Andrew de Quincey
+
+ AC-3 support:
+
+ Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License vs published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
+ */
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -11,6 +35,8 @@
#include "compat.h"
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
#include <linux/init.h>
#include <linux/crc32.h>
@@ -28,9 +54,6 @@ MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
MODULE_AUTHOR("Andrew de Quincey");
MODULE_LICENSE("GPL");
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
enum saa6752hs_videoformat {
SAA6752HS_VF_D1 = 0, /* standard D1 video format: 720x576 */
SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
@@ -47,7 +70,9 @@ struct saa6752hs_mpeg_params {
__u16 ts_pid_pcr;
/* audio */
- enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+ enum v4l2_mpeg_audio_encoding au_encoding;
+ enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+ enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate;
/* video */
enum v4l2_mpeg_video_aspect vi_aspect;
@@ -71,7 +96,9 @@ static const struct v4l2_format v4l2_format_table[] =
};
struct saa6752hs_state {
- struct i2c_client client;
+ int chip;
+ u32 revision;
+ int has_ac3;
struct saa6752hs_mpeg_params params;
enum saa6752hs_videoformat video_format;
v4l2_std_id standard;
@@ -146,6 +173,39 @@ static u8 PMT[] = {
0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
+static u8 PMT_AC3[] = {
+ 0xc2, /* i2c register */
+ 0x01, /* table number for encoder(1) */
+ 0x47, /* sync */
+
+ 0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
+ 0x10, /* PMT PID (0x0010) */
+ 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
+
+ 0x00, /* PSI pointer to start of table */
+
+ 0x02, /* TID (2) */
+ 0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */
+
+ 0x00, 0x01, /* program_number(1) */
+
+ 0xc1, /* version_number(0), current_next_indicator(1) */
+
+ 0x00, 0x00, /* section_number(0), last_section_number(0) */
+
+ 0xe1, 0x04, /* PCR_PID (0x0104) */
+
+ 0xf0, 0x00, /* program_info_length(0) */
+
+ 0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+ 0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */
+ 0x6a, /* AC3 */
+ 0x01, /* Descriptor_length(1) */
+ 0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
+
+ 0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
+};
+
static struct saa6752hs_mpeg_params param_defaults =
{
.ts_pid_pmt = 16,
@@ -158,7 +218,9 @@ static struct saa6752hs_mpeg_params param_defaults =
.vi_bitrate_peak = 6000,
.vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+ .au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
};
/* ---------------------------------------------------------------------- */
@@ -231,8 +293,9 @@ static int saa6752hs_chip_command(struct i2c_client* client,
static int saa6752hs_set_bitrate(struct i2c_client* client,
- struct saa6752hs_mpeg_params* params)
+ struct saa6752hs_state *h)
{
+ struct saa6752hs_mpeg_params *params = &h->params;
u8 buf[3];
int tot_bitrate;
@@ -264,11 +327,19 @@ static int saa6752hs_set_bitrate(struct i2c_client* client,
tot_bitrate = params->vi_bitrate;
}
+ /* set the audio encoding */
+ buf[0] = 0x93;
+ buf[1] = (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3);
+ i2c_master_send(client, buf, 2);
+
/* set the audio bitrate */
buf[0] = 0x94;
- buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
+ if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
+ buf[1] = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate;
+ else
+ buf[1] = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate;
+ tot_bitrate += buf[1] ? 384 : 256;
i2c_master_send(client, buf, 2);
- tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
/* Note: the total max bitrate is determined by adding the video and audio
bitrates together and also adding an extra 768kbit/s to stay on the
@@ -333,7 +404,7 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
}
-static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
struct v4l2_ext_control *ctrl, unsigned int cmd)
{
int old = 0, new;
@@ -380,8 +451,9 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
params->ts_pid_pcr = new;
break;
case V4L2_CID_MPEG_AUDIO_ENCODING:
- old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
- if (set && new != old)
+ old = params->au_encoding;
+ if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+ (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
return -ERANGE;
new = old;
break;
@@ -396,6 +468,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
params->au_l2_bitrate = new;
break;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ if (!has_ac3)
+ return -EINVAL;
+ old = params->au_ac3_bitrate;
+ if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
+ new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
+ return -ERANGE;
+ if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
+ new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
+ else
+ new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
+ params->au_ac3_bitrate = new;
+ break;
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
if (set && new != old)
@@ -449,17 +534,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
return 0;
}
-static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qctrl(struct saa6752hs_state *h,
struct v4l2_queryctrl *qctrl)
{
+ struct saa6752hs_mpeg_params *params = &h->params;
int err;
switch (qctrl->id) {
case V4L2_CID_MPEG_AUDIO_ENCODING:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+ h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
return v4l2_ctrl_query_fill(qctrl,
@@ -467,6 +554,14 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ if (!h->has_ac3)
+ return -EINVAL;
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
@@ -513,44 +608,57 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
return -EINVAL;
}
-static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qmenu(struct saa6752hs_state *h,
struct v4l2_querymenu *qmenu)
{
- static const char *mpeg_audio_l2_bitrate[] = {
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "256 kbps",
- "",
- "384 kbps",
- NULL
+ static const u32 mpeg_audio_encoding[] = {
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_CTRL_MENU_IDS_END
+ };
+ static const u32 mpeg_audio_ac3_encoding[] = {
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_AC3,
+ V4L2_CTRL_MENU_IDS_END
+ };
+ static u32 mpeg_audio_l2_bitrate[] = {
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+ V4L2_CTRL_MENU_IDS_END
+ };
+ static u32 mpeg_audio_ac3_bitrate[] = {
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+ V4L2_CTRL_MENU_IDS_END
};
struct v4l2_queryctrl qctrl;
int err;
qctrl.id = qmenu->id;
- err = saa6752hs_qctrl(params, &qctrl);
+ err = saa6752hs_qctrl(h, &qctrl);
if (err)
return err;
- if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE)
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ switch (qmenu->id) {
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_menu_valid_items(qmenu,
mpeg_audio_l2_bitrate);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- v4l2_ctrl_get_menu(qmenu->id));
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ if (!h->has_ac3)
+ return -EINVAL;
+ return v4l2_ctrl_query_menu_valid_items(qmenu,
+ mpeg_audio_ac3_bitrate);
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_menu_valid_items(qmenu,
+ h->has_ac3 ? mpeg_audio_ac3_encoding :
+ mpeg_audio_encoding);
+ }
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
}
static int saa6752hs_init(struct i2c_client* client)
{
unsigned char buf[9], buf2[4];
struct saa6752hs_state *h;
+ unsigned size;
u32 crc;
unsigned char localPAT[256];
unsigned char localPMT[256];
@@ -570,7 +678,7 @@ static int saa6752hs_init(struct i2c_client* client)
i2c_master_send(client, buf, 2);
/* set bitrate */
- saa6752hs_set_bitrate(client, &h->params);
+ saa6752hs_set_bitrate(client, h);
/* Set GOP structure {3, 13} */
buf[0] = 0x72;
@@ -609,7 +717,13 @@ static int saa6752hs_init(struct i2c_client* client)
localPAT[sizeof(PAT) - 1] = crc & 0xFF;
/* compute PMT */
- memcpy(localPMT, PMT, sizeof(PMT));
+ if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+ size = sizeof(PMT_AC3);
+ memcpy(localPMT, PMT_AC3, size);
+ } else {
+ size = sizeof(PMT);
+ memcpy(localPMT, PMT, size);
+ }
localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
localPMT[4] = h->params.ts_pid_pmt & 0xff;
localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
@@ -618,11 +732,11 @@ static int saa6752hs_init(struct i2c_client* client)
localPMT[21] = h->params.ts_pid_video & 0xFF;
localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
localPMT[26] = h->params.ts_pid_audio & 0xFF;
- crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4);
- localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF;
- localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF;
- localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
- localPMT[sizeof(PMT) - 1] = crc & 0xFF;
+ crc = crc32_be(~0, &localPMT[7], size - 7 - 4);
+ localPMT[size - 4] = (crc >> 24) & 0xFF;
+ localPMT[size - 3] = (crc >> 16) & 0xFF;
+ localPMT[size - 2] = (crc >> 8) & 0xFF;
+ localPMT[size - 1] = crc & 0xFF;
/* Set Audio PID */
buf[0] = 0xC1;
@@ -643,8 +757,8 @@ static int saa6752hs_init(struct i2c_client* client)
i2c_master_send(client,buf,3);
/* Send SI tables */
- i2c_master_send(client,localPAT,sizeof(PAT));
- i2c_master_send(client,localPMT,sizeof(PMT));
+ i2c_master_send(client, localPAT, sizeof(PAT));
+ i2c_master_send(client, localPMT, size);
/* mute then unmute audio. This removes buzzing artefacts */
buf[0] = 0xa4;
@@ -689,45 +803,6 @@ static int saa6752hs_init(struct i2c_client* client)
return 0;
}
-static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- struct saa6752hs_state *h;
-
-
- if (NULL == (h = kzalloc(sizeof(*h), GFP_KERNEL)))
- return -ENOMEM;
- h->client = client_template;
- h->params = param_defaults;
- h->client.adapter = adap;
- h->client.addr = addr;
-
- /* Assume 625 input lines */
- h->standard = 0;
-
- i2c_set_clientdata(&h->client, h);
- i2c_attach_client(&h->client);
-
- v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
- return 0;
-}
-
-static int saa6752hs_probe(struct i2c_adapter *adap)
-{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, saa6752hs_attach);
- return 0;
-}
-
-static int saa6752hs_detach(struct i2c_client *client)
-{
- struct saa6752hs_state *h;
-
- h = i2c_get_clientdata(client);
- i2c_detach_client(client);
- kfree(h);
- return 0;
-}
-
static int
saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
@@ -753,7 +828,8 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL;
params = h->params;
for (i = 0; i < ctrls->count; i++) {
- if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+ err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, cmd);
+ if (err) {
ctrls->error_idx = i;
return err;
}
@@ -761,9 +837,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
h->params = params;
break;
case VIDIOC_QUERYCTRL:
- return saa6752hs_qctrl(&h->params, arg);
+ return saa6752hs_qctrl(h, arg);
case VIDIOC_QUERYMENU:
- return saa6752hs_qmenu(&h->params, arg);
+ return saa6752hs_qmenu(h, arg);
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
@@ -786,6 +862,11 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_S_STD:
h->standard = *((v4l2_std_id *) arg);
break;
+
+ case VIDIOC_G_CHIP_IDENT:
+ return v4l2_chip_ident_i2c_client(client,
+ arg, h->chip, h->revision);
+
default:
/* nothing */
break;
@@ -794,36 +875,59 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
return err;
}
-/* ----------------------------------------------------------------------- */
+static int saa6752hs_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+ u8 addr = 0x13;
+ u8 data[12];
-static struct i2c_driver driver = {
- .driver = {
- .name = "saa6752hs",
- },
- .id = I2C_DRIVERID_SAA6752HS,
- .attach_adapter = saa6752hs_probe,
- .detach_client = saa6752hs_detach,
- .command = saa6752hs_command,
-};
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+ if (h == NULL)
+ return -ENOMEM;
-static struct i2c_client client_template =
-{
- .name = "saa6752hs",
- .driver = &driver,
-};
+ i2c_master_send(client, &addr, 1);
+ i2c_master_recv(client, data, sizeof(data));
+ h->chip = V4L2_IDENT_SAA6752HS;
+ h->revision = (data[8] << 8) | data[9];
+ h->has_ac3 = 0;
+ if (h->revision == 0x0206) {
+ h->chip = V4L2_IDENT_SAA6752HS_AC3;
+ h->has_ac3 = 1;
+ v4l_info(client, "support AC-3\n");
+ }
+ h->params = param_defaults;
+ h->standard = 0; /* Assume 625 input lines */
-static int __init saa6752hs_init_module(void)
-{
- return i2c_add_driver(&driver);
+ i2c_set_clientdata(client, h);
+ return 0;
}
-static void __exit saa6752hs_cleanup_module(void)
+static int saa6752hs_remove(struct i2c_client *client)
{
- i2c_del_driver(&driver);
+ kfree(i2c_get_clientdata(client));
+ return 0;
}
-module_init(saa6752hs_init_module);
-module_exit(saa6752hs_cleanup_module);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa6752hs_id[] = {
+ { "saa6752hs", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa6752hs",
+ .driverid = I2C_DRIVERID_SAA6752HS,
+ .command = saa6752hs_command,
+ .probe = saa6752hs_probe,
+ .remove = saa6752hs_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa6752hs_id,
+#endif
+};
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index e02c3c1b1..117f33946 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -264,7 +264,7 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
{
__le32 *cpu;
- dma_addr_t dma_addr;
+ dma_addr_t dma_addr = 0;
cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
if (NULL == cpu)
@@ -408,32 +408,6 @@ void saa7134_buffer_timeout(unsigned long data)
spin_unlock_irqrestore(&dev->slock,flags);
}
-/* resends a current buffer in queue after resume */
-
-static int saa7134_buffer_requeue(struct saa7134_dev *dev,
- struct saa7134_dmaqueue *q)
-{
- struct saa7134_buf *buf, *next;
-
- assert_spin_locked(&dev->slock);
-
- buf = q->curr;
- next = buf;
- dprintk("buffer_requeue\n");
-
- if (!buf)
- return 0;
-
- dprintk("buffer_requeue : resending active buffers \n");
-
- if (!list_empty(&q->queue))
- next = list_entry(q->queue.next, struct saa7134_buf,
- vb.queue);
- buf->activate(dev, buf, next);
-
- return 0;
-}
-
/* ------------------------------------------------------------------ */
int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -1203,6 +1177,32 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
}
#ifdef CONFIG_PM
+
+/* resends a current buffer in queue after resume */
+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q)
+{
+ struct saa7134_buf *buf, *next;
+
+ assert_spin_locked(&dev->slock);
+
+ buf = q->curr;
+ next = buf;
+ dprintk("buffer_requeue\n");
+
+ if (!buf)
+ return 0;
+
+ dprintk("buffer_requeue : resending active buffers \n");
+
+ if (!list_empty(&q->queue))
+ next = list_entry(q->queue.next, struct saa7134_buf,
+ vb.queue);
+ buf->activate(dev, buf, next);
+
+ return 0;
+}
+
static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
{
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index a454968f7..5225ed6b8 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -29,6 +29,7 @@
#include <media/saa6752hs.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
/* ------------------------------------------------------------------ */
@@ -403,6 +404,25 @@ static int empress_querymenu(struct file *file, void *priv,
return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
}
+static int empress_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_chip_ident *chip)
+{
+ struct saa7134_dev *dev = file->private_data;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (dev->mpeg_i2c_client == NULL)
+ return -EINVAL;
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match_chip == I2C_DRIVERID_SAA6752HS)
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR &&
+ chip->match_chip == dev->mpeg_i2c_client->addr)
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+ return -EINVAL;
+}
+
+
static const struct file_operations ts_fops =
{
.owner = THIS_MODULE,
@@ -431,11 +451,11 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_enum_input = empress_enum_input,
.vidioc_g_input = empress_g_input,
.vidioc_s_input = empress_s_input,
-
.vidioc_queryctrl = empress_queryctrl,
.vidioc_querymenu = empress_querymenu,
.vidioc_g_ctrl = empress_g_ctrl,
.vidioc_s_ctrl = empress_s_ctrl,
+ .vidioc_g_chip_ident = empress_g_chip_ident,
};
/* ----------------------------------------------------------- */
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index 318754e73..76838091d 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -304,9 +304,6 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
"SuperH Mobile CEU driver attached to camera %d\n",
icd->devnum);
- if (pcdev->pdata->enable_camera)
- pcdev->pdata->enable_camera();
-
ret = icd->ops->init(icd);
if (ret)
goto err;
@@ -333,8 +330,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
ceu_write(pcdev, CEIER, 0);
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
icd->ops->release(icd);
- if (pcdev->pdata->disable_camera)
- pcdev->pdata->disable_camera();
dev_info(&icd->dev,
"SuperH Mobile CEU driver detached from camera %d\n",
diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c
index f4ebfd84b..2d3d430c5 100644
--- a/linux/drivers/media/video/tda9840.c
+++ b/linux/drivers/media/video/tda9840.c
@@ -2,6 +2,7 @@
tda9840 - i2c-driver for the tda9840 by SGS Thomson
Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+ Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
The tda9840 is a stereo/dual sound processor with digital
identification. It can be found at address 0x84 on the i2c-bus.
@@ -28,16 +29,19 @@
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include "tda9840.h"
#include "compat.h"
-#include "tda9840.h"
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tda9840 driver");
+MODULE_LICENSE("GPL");
-static int debug; /* insmod parameter */
+static int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
-#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define SWITCH 0x00
#define LEVEL_ADJUST 0x02
@@ -50,18 +54,21 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+static void tda9840_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ if (i2c_smbus_write_byte_data(client, reg, val))
+ v4l_dbg(1, debug, client, "error writing %02x to %02x\n",
+ val, reg);
+}
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
{
int result;
int byte = *(int *)arg;
switch (cmd) {
case TDA9840_SWITCH:
-
- dprintk("TDA9840_SWITCH: 0x%02x\n", byte);
+ v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
if (byte != TDA9840_SET_MONO
&& byte != TDA9840_SET_MUTE
@@ -74,14 +81,11 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL;
}
- result = i2c_smbus_write_byte_data(client, SWITCH, byte);
- if (result)
- dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+ tda9840_write(client, SWITCH, byte);
break;
case TDA9840_LEVEL_ADJUST:
-
- dprintk("TDA9840_LEVEL_ADJUST: %d\n", byte);
+ v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte);
/* check for correct range */
if (byte > 25 || byte < -20)
@@ -93,15 +97,11 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
byte += 0x8;
else
byte = -byte;
-
- result = i2c_smbus_write_byte_data(client, LEVEL_ADJUST, byte);
- if (result)
- dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+ tda9840_write(client, LEVEL_ADJUST, byte);
break;
case TDA9840_STEREO_ADJUST:
-
- dprintk("TDA9840_STEREO_ADJUST: %d\n", byte);
+ v4l_dbg(1, debug, client, "TDA9840_STEREO_ADJUST: %d\n", byte);
/* check for correct range */
if (byte > 25 || byte < -24)
@@ -114,9 +114,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
else
byte = -byte;
- result = i2c_smbus_write_byte_data(client, STEREO_ADJUST, byte);
- if (result)
- dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+ tda9840_write(client, STEREO_ADJUST, byte);
break;
case TDA9840_DETECT: {
@@ -124,29 +122,29 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
byte = i2c_smbus_read_byte_data(client, STEREO_ADJUST);
if (byte == -1) {
- dprintk("i2c_smbus_read_byte_data() failed\n");
+ v4l_dbg(1, debug, client,
+ "i2c_smbus_read_byte_data() failed\n");
return -EIO;
}
- if (0 != (byte & 0x80)) {
- dprintk("TDA9840_DETECT: register contents invalid\n");
+ if (byte & 0x80) {
+ v4l_dbg(1, debug, client,
+ "TDA9840_DETECT: register contents invalid\n");
return -EINVAL;
}
- dprintk("TDA9840_DETECT: byte: 0x%02x\n", byte);
- *ret = ((byte & 0x60) >> 5);
+ v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+ *ret = (byte & 0x60) >> 5;
result = 0;
break;
}
case TDA9840_TEST:
- dprintk("TDA9840_TEST: 0x%02x\n", byte);
+ v4l_dbg(1, debug, client, "TDA9840_TEST: 0x%02x\n", byte);
/* mask out irrelevant bits */
byte &= 0x3;
- result = i2c_smbus_write_byte_data(client, TEST, byte);
- if (result)
- dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+ tda9840_write(client, TEST, byte);
break;
default:
return -ENOIOCTLCMD;
@@ -158,99 +156,55 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
}
-static int detect(struct i2c_adapter *adapter, int address, int kind)
+static int tda9840_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct i2c_client *client;
- int result = 0;
-
- int byte = 0x0;
+ int result;
+ int byte;
/* let's see whether this adapter can support what we need */
- if (0 == i2c_check_functionality(adapter,
- I2C_FUNC_SMBUS_READ_BYTE_DATA |
- I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return 0;
- }
- /* allocate memory for client structure */
- client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client) {
- printk("not enough kernel memory\n");
- return -ENOMEM;
- }
-
- /* fill client structure */
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->addr = address;
- client->adapter = adapter;
-
- /* tell the i2c layer a new client has arrived */
- if (0 != (result = i2c_attach_client(client))) {
- kfree(client);
- return result;
- }
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
/* set initial values for level & stereo - adjustment, mode */
byte = 0;
- result = command(client, TDA9840_LEVEL_ADJUST, &byte);
- result += command(client, TDA9840_STEREO_ADJUST, &byte);
+ result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte);
+ result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte);
byte = TDA9840_SET_MONO;
- result = command(client, TDA9840_SWITCH, &byte);
+ result = tda9840_command(client, TDA9840_SWITCH, &byte);
if (result) {
- dprintk("could not initialize tda9840\n");
+ v4l_dbg(1, debug, client, "could not initialize tda9840\n");
return -ENODEV;
}
-
- printk("tda9840: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
return 0;
}
-static int attach(struct i2c_adapter *adapter)
+static int tda9840_legacy_probe(struct i2c_adapter *adapter)
{
- /* let's see whether this is a know adapter we can attach to */
- if (adapter->id != I2C_HW_SAA7146) {
- dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
- return -ENODEV;
- }
-
- return i2c_probe(adapter, &addr_data, &detect);
+ /* Let's see whether this is a known adapter we can attach to.
+ Prevents conflicts with tvaudio.c. */
+ return adapter->id == I2C_HW_SAA7146;
}
-
-static int detach(struct i2c_client *client)
-{
- int ret = i2c_detach_client(client);
- kfree(client);
- return ret;
-}
-
-static struct i2c_driver driver = {
- .driver = {
- .name = "tda9840",
- },
- .id = I2C_DRIVERID_TDA9840,
- .attach_adapter = attach,
- .detach_client = detach,
- .command = command,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tda9840_id[] = {
+ { "tda9840", 0 },
+ { }
};
+MODULE_DEVICE_TABLE(i2c, tda9840_id);
+#endif
-static struct i2c_client client_template = {
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tda9840",
- .driver = &driver,
+ .driverid = I2C_DRIVERID_TDA9840,
+ .command = tda9840_command,
+ .probe = tda9840_probe,
+ .legacy_probe = tda9840_legacy_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tda9840_id,
+#endif
};
-
-static int __init this_module_init(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit this_module_exit(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(this_module_init);
-module_exit(this_module_exit);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tda9840 driver");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c
index da654bd15..073f020fa 100644
--- a/linux/drivers/media/video/tea6415c.c
+++ b/linux/drivers/media/video/tea6415c.c
@@ -2,6 +2,7 @@
tea6415c - i2c-driver for the tea6415c by SGS Thomson
Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+ Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
The tea6415c is a bus controlled video-matrix-switch
with 8 inputs and 6 outputs.
@@ -30,19 +31,19 @@
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include "tea6415c.h"
#include "compat.h"
-#include "tea6415c.h"
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6415c driver");
+MODULE_LICENSE("GPL");
-static int debug; /* insmod parameter */
+static int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
-
-#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
-#define TEA6415C_NUM_INPUTS 8
-#define TEA6415C_NUM_OUTPUTS 6
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
@@ -50,60 +51,6 @@ static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIEN
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-/* this function is called by i2c_probe */
-static int detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *client = NULL;
- int err = 0;
-
- /* let's see whether this adapter can support what we need */
- if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) {
- return 0;
- }
-
- /* allocate memory for client structure */
- client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client) {
- return -ENOMEM;
- }
-
- /* fill client structure */
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->addr = address;
- client->adapter = adapter;
-
- /* tell the i2c layer a new client has arrived */
- if (0 != (err = i2c_attach_client(client))) {
- kfree(client);
- return err;
- }
-
- printk("tea6415c: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
-
- return 0;
-}
-
-static int attach(struct i2c_adapter *adapter)
-{
- /* let's see whether this is a know adapter we can attach to */
- if (adapter->id != I2C_HW_SAA7146) {
- dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
- return -ENODEV;
- }
-
- return i2c_probe(adapter, &addr_data, &detect);
-}
-
-static int detach(struct i2c_client *client)
-{
- int ret = i2c_detach_client(client);
- kfree(client);
- return ret;
-}
-
/* makes a connection between the input-pin 'i' and the output-pin 'o'
for the tea6415c-client 'client' */
static int switch_matrix(struct i2c_client *client, int i, int o)
@@ -111,7 +58,7 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
u8 byte = 0;
int ret;
- dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o);
+ v4l_dbg(1, debug, client, "i=%d, o=%d\n", i, o);
/* check if the pins are valid */
if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i)
@@ -169,14 +116,14 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
ret = i2c_smbus_write_byte(client, byte);
if (ret) {
- dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
+ v4l_dbg(1, debug, client,
+ "i2c_smbus_write_byte() failed, ret:%d\n", ret);
return -EIO;
}
-
return ret;
}
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
int result = 0;
@@ -188,38 +135,44 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
default:
return -ENOIOCTLCMD;
}
-
return result;
}
-static struct i2c_driver driver = {
- .driver = {
- .name = "tea6415c",
- },
- .id = I2C_DRIVERID_TEA6415C,
- .attach_adapter = attach,
- .detach_client = detach,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- .name = "tea6415c",
- .driver = &driver,
-};
-
-static int __init this_module_init(void)
+/* this function is called by i2c_probe */
+static int tea6415c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- return i2c_add_driver(&driver);
+ /* let's see whether this adapter can support what we need */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+ return 0;
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+ return 0;
}
-static void __exit this_module_exit(void)
+static int tea6415c_legacy_probe(struct i2c_adapter *adapter)
{
- i2c_del_driver(&driver);
+ /* Let's see whether this is a known adapter we can attach to.
+ Prevents conflicts with tvaudio.c. */
+ return adapter->id == I2C_HW_SAA7146;
}
-module_init(this_module_init);
-module_exit(this_module_exit);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tea6415c_id[] = {
+ { "tea6415c", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tea6415c_id);
+#endif
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tea6415c driver");
-MODULE_LICENSE("GPL");
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tea6415c",
+ .driverid = I2C_DRIVERID_TEA6415C,
+ .command = tea6415c_command,
+ .probe = tea6415c_probe,
+ .legacy_probe = tea6415c_legacy_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tea6415c_id,
+#endif
+};
diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c
index d0c63703c..8ded72ade 100644
--- a/linux/drivers/media/video/tea6420.c
+++ b/linux/drivers/media/video/tea6420.c
@@ -2,6 +2,7 @@
tea6420 - i2c-driver for the tea6420 by SGS Thomson
Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+ Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
The tea6420 is a bus controlled audio-matrix with 5 stereo inputs,
4 stereo outputs and gain control for each output.
@@ -30,16 +31,19 @@
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include "tea6420.h"
#include "compat.h"
-#include "tea6420.h"
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6420 driver");
+MODULE_LICENSE("GPL");
-static int debug; /* insmod parameter */
+static int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
-#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
@@ -47,23 +51,20 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
/* make a connection between the input 'i' and the output 'o'
with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */
static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
{
- u8 byte = 0;
+ u8 byte;
int ret;
- dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g);
+ v4l_dbg(1, debug, client, "i=%d, o=%d, g=%d\n", i, o, g);
/* check if the parameters are valid */
if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
return -1;
- byte = ((o - 1) << 5);
+ byte = ((o - 1) << 5);
byte |= (i - 1);
/* to understand this, have a look at the tea6420-specs (p.5) */
@@ -83,40 +84,41 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
ret = i2c_smbus_write_byte(client, byte);
if (ret) {
- dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
+ v4l_dbg(1, debug, client,
+ "i2c_smbus_write_byte() failed, ret:%d\n", ret);
return -EIO;
}
-
return 0;
}
-/* this function is called by i2c_probe */
-static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
+static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
{
- struct i2c_client *client;
- int err = 0, i = 0;
+ struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
+ int result = 0;
- /* let's see whether this adapter can support what we need */
- if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) {
- return 0;
+ switch (cmd) {
+ case TEA6420_SWITCH:
+ result = tea6420_switch(client, a->in, a->out, a->gain);
+ break;
+ default:
+ return -ENOIOCTLCMD;
}
- /* allocate memory for client structure */
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client) {
- return -ENOMEM;
- }
+ return result;
+}
- /* fill client structure */
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->addr = address;
- client->adapter = adapter;
+/* this function is called by i2c_probe */
+static int tea6420_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err, i;
- /* tell the i2c layer a new client has arrived */
- if (0 != (err = i2c_attach_client(client))) {
- kfree(client);
- return err;
- }
+ /* let's see whether this adapter can support what we need */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+ return -EIO;
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
/* set initial values: set "mute"-input to all outputs at gain 0 */
err = 0;
@@ -124,78 +126,35 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
err += tea6420_switch(client, 6, i, 0);
}
if (err) {
- dprintk("could not initialize tea6420\n");
+ v4l_dbg(1, debug, client, "could not initialize tea6420\n");
kfree(client);
return -ENODEV;
}
-
- printk("tea6420: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
-
return 0;
}
-static int attach(struct i2c_adapter *adapter)
+static int tea6420_legacy_probe(struct i2c_adapter *adapter)
{
- /* let's see whether this is a know adapter we can attach to */
- if (adapter->id != I2C_HW_SAA7146) {
- dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
- return -ENODEV;
- }
-
- return i2c_probe(adapter, &addr_data, &tea6420_detect);
-}
-
-static int detach(struct i2c_client *client)
-{
- int ret = i2c_detach_client(client);
- kfree(client);
- return ret;
-}
-
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
- int result = 0;
-
- switch (cmd) {
- case TEA6420_SWITCH:
- result = tea6420_switch(client, a->in, a->out, a->gain);
- break;
- default:
- return -ENOIOCTLCMD;
- }
-
- return result;
+ /* Let's see whether this is a known adapter we can attach to.
+ Prevents conflicts with tvaudio.c. */
+ return adapter->id == I2C_HW_SAA7146;
}
-static struct i2c_driver driver = {
- .driver = {
- .name = "tea6420",
- },
- .id = I2C_DRIVERID_TEA6420,
- .attach_adapter = attach,
- .detach_client = detach,
- .command = command,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tea6420_id[] = {
+ { "tea6420", 0 },
+ { }
};
+MODULE_DEVICE_TABLE(i2c, tea6420_id);
+#endif
-static struct i2c_client client_template = {
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tea6420",
- .driver = &driver,
+ .driverid = I2C_DRIVERID_TEA6420,
+ .command = tea6420_command,
+ .probe = tea6420_probe,
+ .legacy_probe = tea6420_legacy_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tea6420_id,
+#endif
};
-
-static int __init this_module_init(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit this_module_exit(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(this_module_init);
-module_exit(this_module_exit);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tea6420 driver");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/tuner-3036.c b/linux/drivers/media/video/tuner-3036.c
deleted file mode 100644
index 8b87d75f4..000000000
--- a/linux/drivers/media/video/tuner-3036.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Driver for Philips SAB3036 "CITAC" tuner control chip.
- *
- * Author: Phil Blundell <philb@gnu.org>
- *
- * The SAB3036 is just about different enough from the chips that
- * tuner.c copes with to make it not worth the effort to crowbar
- * the support into that file. So instead we have a separate driver.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <linux/i2c.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-
-#include <media/tuner.h>
-
-static int debug; /* insmod parameter */
-static int this_adap;
-
-static struct i2c_client client_template;
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END };
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .probe = &ignore,
- .ignore = &ignore,
-};
-
-/* ---------------------------------------------------------------------- */
-
-static unsigned char
-tuner_getstatus (struct i2c_client *c)
-{
- unsigned char byte;
- if (i2c_master_recv(c, &byte, 1) != 1)
- printk(KERN_ERR "tuner-3036: I/O error.\n");
- return byte;
-}
-
-#define TUNER_FL 0x80
-
-static int
-tuner_islocked (struct i2c_client *c)
-{
- return (tuner_getstatus(c) & TUNER_FL);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void
-set_tv_freq(struct i2c_client *c, int freq)
-{
- u16 div = ((freq * 20) / 16);
- unsigned long give_up = jiffies + HZ;
- unsigned char buffer[2];
-
- if (debug)
- printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div);
-
- /* Select high tuning current */
- buffer[0] = 0x29;
- buffer[1] = 0x3e;
-
- if (i2c_master_send(c, buffer, 2) != 2)
- printk("tuner: i2c i/o error 1\n");
-
- buffer[0] = 0x80 | ((div>>8) & 0x7f);
- buffer[1] = div & 0xff;
-
- if (i2c_master_send(c, buffer, 2) != 2)
- printk("tuner: i2c i/o error 2\n");
-
- while (!tuner_islocked(c) && time_before(jiffies, give_up))
- schedule();
-
- if (!tuner_islocked(c))
- printk(KERN_WARNING "tuner: failed to achieve PLL lock\n");
-
- /* Select low tuning current and engage AFC */
- buffer[0] = 0x29;
- buffer[1] = 0xb2;
-
- if (i2c_master_send(c, buffer, 2) != 2)
- printk("tuner: i2c i/o error 3\n");
-
- if (debug)
- printk(KERN_DEBUG "tuner: status %02x\n", tuner_getstatus(c));
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int
-tuner_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 };
-
- struct i2c_client *client;
-
- if (this_adap > 0)
- return -1;
- this_adap++;
-
- client_template.adapter = adap;
- client_template.addr = addr;
-
- client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == NULL)
- return -ENOMEM;
- memcpy(client, &client_template, sizeof(struct i2c_client));
-
- printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client));
-
- i2c_attach_client(client);
-
- if (i2c_master_send(client, buffer, 2) != 2)
- printk("tuner: i2c i/o error 1\n");
- if (i2c_master_send(client, buffer+2, 2) != 2)
- printk("tuner: i2c i/o error 2\n");
- if (i2c_master_send(client, buffer+4, 2) != 2)
- printk("tuner: i2c i/o error 3\n");
- return 0;
-}
-
-static int
-tuner_detach(struct i2c_client *c)
-{
- return 0;
-}
-
-static int
-tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- int *iarg = (int*)arg;
-
- switch (cmd)
- {
- case VIDIOCSFREQ:
- set_tv_freq(client, *iarg);
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int
-tuner_probe(struct i2c_adapter *adap)
-{
- this_adap = 0;
- if (adap->id == I2C_HW_B_LP)
- return i2c_probe(adap, &addr_data, tuner_attach);
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver
-i2c_driver_tuner =
-{
- .driver = {
- .name = "sab3036",
- },
- .id = I2C_DRIVERID_SAB3036,
- .attach_adapter = tuner_probe,
- .detach_client = tuner_detach,
- .command = tuner_command
-};
-
-static struct i2c_client client_template =
-{
- .driver = &i2c_driver_tuner,
- .name = "SAB3036",
-};
-
-static int __init
-tuner3036_init(void)
-{
- return i2c_add_driver(&i2c_driver_tuner);
-}
-
-static void __exit
-tuner3036_exit(void)
-{
- i2c_del_driver(&i2c_driver_tuner);
-}
-
-MODULE_DESCRIPTION("SAB3036 tuner driver");
-MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
-MODULE_LICENSE("GPL");
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,"Enable debugging output");
-
-module_init(tuner3036_init);
-module_exit(tuner3036_exit);
diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c
index 1afbcc147..697e74a24 100644
--- a/linux/drivers/media/video/usbvideo/ibmcam.c
+++ b/linux/drivers/media/video/usbvideo/ibmcam.c
@@ -736,12 +736,12 @@ static enum ParseState ibmcam_model2_320x240_parse_lines(
* make black color and quit the horizontal scanning loop.
*/
if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
- const int j = i * V4L_BYTES_PER_PIXEL;
+ const int offset = i * V4L_BYTES_PER_PIXEL;
#if USES_IBMCAM_PUTPIXEL
/* Refresh 'f' because we don't use it much with PUTPIXEL */
- f = frame->data + (v4l_linesize * frame->curline) + j;
+ f = frame->data + (v4l_linesize * frame->curline) + offset;
#endif
- memset(f, 0, v4l_linesize - j);
+ memset(f, 0, v4l_linesize - offset);
break;
}
diff --git a/linux/drivers/media/video/usbvideo/usbvideo.c b/linux/drivers/media/video/usbvideo/usbvideo.c
index 5bda83f7d..4b28a6dfb 100644
--- a/linux/drivers/media/video/usbvideo/usbvideo.c
+++ b/linux/drivers/media/video/usbvideo/usbvideo.c
@@ -1006,6 +1006,10 @@ allocate_done:
EXPORT_SYMBOL(usbvideo_AllocateDevice);
+static void usbvideo_dummy_release(struct video_device *vfd)
+{
+}
+
int usbvideo_RegisterVideoDevice(struct uvd *uvd)
{
char tmp1[20], tmp2[20]; /* Buffers for printing */
@@ -1039,7 +1043,8 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
return -EINVAL;
}
uvd->vdev.parent = &uvd->dev->dev;
- if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ uvd->vdev.release = usbvideo_dummy_release;
+ if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
err("%s: video_register_device failed", __func__);
return -EPIPE;
}
diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c
index 7e102034d..4a2d09988 100644
--- a/linux/drivers/media/video/uvc/uvc_driver.c
+++ b/linux/drivers/media/video/uvc/uvc_driver.c
@@ -1663,7 +1663,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
return uvc_video_suspend(&dev->video);
}
-static int uvc_resume(struct usb_interface *intf)
+static int __uvc_resume(struct usb_interface *intf, int reset)
{
struct uvc_device *dev = usb_get_intfdata(intf);
int ret;
@@ -1672,7 +1672,7 @@ static int uvc_resume(struct usb_interface *intf)
intf->cur_altsetting->desc.bInterfaceNumber);
if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
- if ((ret = uvc_ctrl_resume_device(dev)) < 0)
+ if (reset && (ret = uvc_ctrl_resume_device(dev)) < 0)
return ret;
return uvc_status_resume(dev);
@@ -1687,6 +1687,16 @@ static int uvc_resume(struct usb_interface *intf)
return uvc_video_resume(&dev->video);
}
+static int uvc_resume(struct usb_interface *intf)
+{
+ return __uvc_resume(intf, 0);
+}
+
+static int uvc_reset_resume(struct usb_interface *intf)
+{
+ return __uvc_resume(intf, 1);
+}
+
/* ------------------------------------------------------------------------
* Driver initialization and cleanup
*/
@@ -1952,6 +1962,7 @@ struct uvc_driver uvc_driver = {
.disconnect = uvc_disconnect,
.suspend = uvc_suspend,
.resume = uvc_resume,
+ .reset_resume = uvc_reset_resume,
.id_table = uvc_ids,
.supports_autosuspend = 1,
},
diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c
index 6854ac78a..03dc3a519 100644
--- a/linux/drivers/media/video/uvc/uvc_video.c
+++ b/linux/drivers/media/video/uvc/uvc_video.c
@@ -655,7 +655,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
if (size > UVC_MAX_FRAME_SIZE)
return -EINVAL;
- npackets = (size + psize - 1) / psize;
+ npackets = DIV_ROUND_UP(size, psize);
if (npackets > UVC_MAX_ISO_PACKETS)
npackets = UVC_MAX_ISO_PACKETS;
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index a027d9baa..b5baf8f7e 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -188,9 +188,11 @@ const char **v4l2_ctrl_get_menu(u32 id)
NULL
};
static const char *mpeg_audio_encoding[] = {
- "Layer I",
- "Layer II",
- "Layer III",
+ "MPEG-1/2 Layer I",
+ "MPEG-1/2 Layer II",
+ "MPEG-1/2 Layer III",
+ "MPEG-2/4 AAC",
+ "AC-3",
NULL
};
static const char *mpeg_audio_l1_bitrate[] = {
@@ -244,6 +246,28 @@ const char **v4l2_ctrl_get_menu(u32 id)
"320 kbps",
NULL
};
+ static const char *mpeg_audio_ac3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ "448 kbps",
+ "512 kbps",
+ "576 kbps",
+ "640 kbps",
+ NULL
+ };
static const char *mpeg_audio_mode[] = {
"Stereo",
"Joint Stereo",
@@ -272,6 +296,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
static const char *mpeg_video_encoding[] = {
"MPEG-1",
"MPEG-2",
+ "MPEG-4 AVC",
NULL
};
static const char *mpeg_video_aspect[] = {
@@ -312,6 +337,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
return mpeg_audio_l2_bitrate;
case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
return mpeg_audio_l3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ return mpeg_audio_ac3_bitrate;
case V4L2_CID_MPEG_AUDIO_MODE:
return mpeg_audio_mode;
case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
@@ -336,62 +363,73 @@ const char **v4l2_ctrl_get_menu(u32 id)
}
EXPORT_SYMBOL(v4l2_ctrl_get_menu);
-/* Fill in a struct v4l2_queryctrl */
-int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+/* Return the control name. */
+const char *v4l2_ctrl_get_name(u32 id)
{
- const char *name;
-
- qctrl->flags = 0;
- switch (qctrl->id) {
+ switch (id) {
/* USER controls */
- case V4L2_CID_USER_CLASS: name = "User Controls"; break;
- case V4L2_CID_AUDIO_VOLUME: name = "Volume"; break;
- case V4L2_CID_AUDIO_MUTE: name = "Mute"; break;
- case V4L2_CID_AUDIO_BALANCE: name = "Balance"; break;
- case V4L2_CID_AUDIO_BASS: name = "Bass"; break;
- case V4L2_CID_AUDIO_TREBLE: name = "Treble"; break;
- case V4L2_CID_AUDIO_LOUDNESS: name = "Loudness"; break;
- case V4L2_CID_BRIGHTNESS: name = "Brightness"; break;
- case V4L2_CID_CONTRAST: name = "Contrast"; break;
- case V4L2_CID_SATURATION: name = "Saturation"; break;
- case V4L2_CID_HUE: name = "Hue"; break;
+ case V4L2_CID_USER_CLASS: return "User Controls";
+ case V4L2_CID_AUDIO_VOLUME: return "Volume";
+ case V4L2_CID_AUDIO_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_BALANCE: return "Balance";
+ case V4L2_CID_AUDIO_BASS: return "Bass";
+ case V4L2_CID_AUDIO_TREBLE: return "Treble";
+ case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
+ case V4L2_CID_BRIGHTNESS: return "Brightness";
+ case V4L2_CID_CONTRAST: return "Contrast";
+ case V4L2_CID_SATURATION: return "Saturation";
+ case V4L2_CID_HUE: return "Hue";
/* MPEG controls */
- case V4L2_CID_MPEG_CLASS: name = "MPEG Encoder Controls"; break;
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
- case V4L2_CID_MPEG_AUDIO_ENCODING: name = "Audio Encoding Layer"; break;
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE: name = "Audio Layer I Bitrate"; break;
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE: name = "Audio Layer II Bitrate"; break;
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE: name = "Audio Layer III Bitrate"; break;
- case V4L2_CID_MPEG_AUDIO_MODE: name = "Audio Stereo Mode"; break;
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
- case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break;
- case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break;
- case V4L2_CID_MPEG_AUDIO_MUTE: name = "Audio Mute"; break;
- case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break;
- case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break;
- case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break;
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE: name = "Video GOP Size"; break;
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: name = "Video GOP Closure"; break;
- case V4L2_CID_MPEG_VIDEO_PULLDOWN: name = "Video Pulldown"; break;
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: name = "Video Bitrate Mode"; break;
- case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break;
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break;
- case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
- case V4L2_CID_MPEG_VIDEO_MUTE: name = "Video Mute"; break;
- case V4L2_CID_MPEG_VIDEO_MUTE_YUV: name = "Video Mute YUV"; break;
- case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break;
- case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break;
- case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break;
- case V4L2_CID_MPEG_STREAM_PID_VIDEO: name = "Stream Video Program ID"; break;
- case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break;
- case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
- case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
- case V4L2_CID_MPEG_STREAM_VBI_FMT: name = "Stream VBI Format"; break;
+ case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
+ case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
+ case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
+ case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
+ case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
+ case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
+ case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
+ case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
+ case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
+ case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
+ case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
+ case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
default:
- return -EINVAL;
+ return NULL;
}
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_name);
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name = v4l2_ctrl_get_name(qctrl->id);
+
+ qctrl->flags = 0;
+ if (name == NULL)
+ return -EINVAL;
+
switch (qctrl->id) {
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_LOUDNESS:
@@ -408,6 +446,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
case V4L2_CID_MPEG_AUDIO_MODE:
case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
case V4L2_CID_MPEG_AUDIO_EMPHASIS:
@@ -494,7 +533,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
case V4L2_CID_MPEG_AUDIO_ENCODING:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+ V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
return v4l2_ctrl_query_fill(qctrl,
@@ -511,6 +550,13 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
V4L2_MPEG_AUDIO_L3_BITRATE_32K,
V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+ case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000);
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_32K,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K);
case V4L2_CID_MPEG_AUDIO_MODE:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_AUDIO_MODE_STEREO,
@@ -536,7 +582,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
case V4L2_CID_MPEG_VIDEO_ENCODING:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
case V4L2_CID_MPEG_VIDEO_ASPECT:
return v4l2_ctrl_query_fill(qctrl,
@@ -595,12 +641,17 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
- the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+ the menu. The qctrl pointer may be NULL, in which case it is ignored.
+ If menu_items is NULL, then the menu items are retrieved using
+ v4l2_ctrl_get_menu. */
int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
const char **menu_items)
{
int i;
+ qmenu->reserved = 0;
+ if (menu_items == NULL)
+ menu_items = v4l2_ctrl_get_menu(qmenu->id);
if (menu_items == NULL ||
(qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
return -EINVAL;
@@ -608,11 +659,31 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
if (menu_items[i] == NULL || menu_items[i][0] == '\0')
return -EINVAL;
snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
- qmenu->reserved = 0;
return 0;
}
EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+/* Fill in a struct v4l2_querymenu based on the specified array of valid
+ menu items (terminated by V4L2_CTRL_MENU_IDS_END).
+ Use this if there are 'holes' in the list of valid menu items. */
+int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
+{
+ const char **menu_items = v4l2_ctrl_get_menu(qmenu->id);
+
+ qmenu->reserved = 0;
+ if (menu_items == NULL || ids == NULL)
+ return -EINVAL;
+ while (*ids != V4L2_CTRL_MENU_IDS_END) {
+ if (*ids++ == qmenu->index) {
+ snprintf(qmenu->name, sizeof(qmenu->name),
+ menu_items[qmenu->index]);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
+
/* ctrl_classes points to an array of u32 pointers, the last element is
a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
Each array must be sorted low to high and belong to the same control
diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c
index 398376a40..a3d52e7f7 100644
--- a/linux/drivers/media/video/v4l2-dev.c
+++ b/linux/drivers/media/video/v4l2-dev.c
@@ -292,6 +292,9 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
int ret;
char *name_base;
+ if (vfd == NULL)
+ return -EINVAL;
+
switch (type) {
case VFL_TYPE_GRABBER:
base = MINOR_VFL_TYPE_GRABBER_MIN;
@@ -316,7 +319,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
default:
printk(KERN_ERR "%s called with unknown type: %d\n",
__func__, type);
- return -1;
+ return -EINVAL;
}
/* pick a minor number */
@@ -356,10 +359,8 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
/* sysfs class */
memset(&vfd->dev, 0x00, sizeof(vfd->dev));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
vfd->dev.class = &video_class;
vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
-#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
if (vfd->parent)
vfd->dev.dev = vfd->parent;
diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c
index a56e3643b..51569f888 100644
--- a/linux/drivers/media/video/v4l2-ioctl.c
+++ b/linux/drivers/media/video/v4l2-ioctl.c
@@ -500,7 +500,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
p->timestamp.tv_sec / 3600,
(int)(p->timestamp.tv_sec / 60) % 60,
(int)(p->timestamp.tv_sec % 60),
- p->timestamp.tv_usec,
+ (long)p->timestamp.tv_usec,
p->index,
prt_names(p->type, v4l2_type_names),
p->bytesused, p->flags,
@@ -675,7 +675,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
__video_do_ioctl will be called again, with one or more
V4L2 ioctls.
********************************************************/
- if (_IOC_TYPE(cmd) == 'v')
+ if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
return v4l_compat_translate_ioctl(inode, file, cmd, arg,
__video_do_ioctl);
#endif
diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c
index 9ada3fff2..1e61b3e5a 100644
--- a/linux/drivers/media/video/vino.c
+++ b/linux/drivers/media/video/vino.c
@@ -809,7 +809,7 @@ static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
dprintk("vino_free_buffer_with_count(): count = %d\n", count);
for (i = 0; i < count; i++) {
- ClearPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+ ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
dma_unmap_single(NULL,
fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
PAGE_SIZE, DMA_FROM_DEVICE);
@@ -887,7 +887,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb,
dma_data_addr + VINO_PAGE_SIZE * j;
}
- SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+ SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
}
/* page_count needs to be set anyway, because the descriptor table has
@@ -974,7 +974,7 @@ static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
dma_data_addr + VINO_PAGE_SIZE * j;
}
- SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+ SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
}
/* page_count needs to be set anyway, because the descriptor table has
diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c
index 2f18381b6..d345aed08 100644
--- a/linux/drivers/media/video/vivi.c
+++ b/linux/drivers/media/video/vivi.c
@@ -1112,19 +1112,29 @@ static struct video_device vivi_template = {
Initialization and module stuff
------------------------------------------------------------------*/
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+ The real maximum number of virtual drivers will depend on how many drivers
+ will succeed. This is limited to the maximum number of devices that
+ videodev supports. Since there are 64 minors for video grabbers, this is
+ currently the theoretical maximum limit. However, a further limit does
+ exist at videodev that forbids any driver to register more than 32 video
+ grabbers.
+ */
static int __init vivi_init(void)
{
int ret = -ENOMEM, i;
struct vivi_dev *dev;
struct video_device *vfd;
+ if (n_devs <= 0)
+ n_devs = 1;
+
for (i = 0; i < n_devs; i++) {
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (NULL == dev)
+ if (!dev)
break;
- list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
init_waitqueue_head(&dev->vidq.wq);
@@ -1134,14 +1144,27 @@ static int __init vivi_init(void)
mutex_init(&dev->mutex);
vfd = video_device_alloc();
- if (NULL == vfd)
+ if (!vfd) {
+ kfree(dev);
break;
+ }
*vfd = vivi_template;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
- if (ret < 0)
+ if (ret < 0) {
+ video_device_release(vfd);
+ kfree(dev);
+
+ /* If some registers succeeded, keep driver */
+ if (i)
+ ret = 0;
+
break;
+ }
+
+ /* Now that everything is fine, let's add it to device list */
+ list_add_tail(&dev->vivi_devlist, &vivi_devlist);
snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
vivi_template.name, vfd->minor);
@@ -1157,11 +1180,16 @@ static int __init vivi_init(void)
if (ret < 0) {
vivi_release();
printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
- } else
+ } else {
printk(KERN_INFO "Video Technology Magazine Virtual Video "
"Capture Board ver %u.%u.%u successfully loaded.\n",
(VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
VIVI_VERSION & 0xFF);
+
+ /* n_devs will reflect the actual number of allocated devices */
+ n_devs = i;
+ }
+
return ret;
}
@@ -1177,10 +1205,10 @@ MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
MODULE_LICENSE("Dual BSD/GPL");
-module_param(video_nr, int, 0);
+module_param(video_nr, uint, 0444);
MODULE_PARM_DESC(video_nr, "video iminor start number");
-module_param(n_devs, int, 0);
+module_param(n_devs, uint, 0444);
MODULE_PARM_DESC(n_devs, "number of video devices to create");
module_param_named(debug, vivi_template.debug, int, 0444);
diff --git a/linux/drivers/media/video/zoran_device.c b/linux/drivers/media/video/zoran_device.c
index b0a014d09..e57da2d6f 100644
--- a/linux/drivers/media/video/zoran_device.c
+++ b/linux/drivers/media/video/zoran_device.c
@@ -378,7 +378,7 @@ zr36057_set_vfe (struct zoran *zr,
/* horizontal */
VidWinWid = video_width;
- X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
+ X = DIV_ROUND_UP(VidWinWid * 64, tvn->Wa);
We = (VidWinWid * 64) / X;
HorDcm = 64 - X;
hcrop1 = 2 * ((tvn->Wa - We) / 4);
@@ -404,7 +404,7 @@ zr36057_set_vfe (struct zoran *zr,
/* Vertical */
DispMode = !(video_height > BUZ_MAX_HEIGHT / 2);
VidWinHt = DispMode ? video_height : video_height / 2;
- Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
+ Y = DIV_ROUND_UP(VidWinHt * 64 * 2, tvn->Ha);
He = (VidWinHt * 64) / Y;
VerDcm = 64 - Y;
vcrop1 = (tvn->Ha / 2 - He) / 2;
diff --git a/linux/drivers/media/video/zoran_procfs.c b/linux/drivers/media/video/zoran_procfs.c
index d7bc097da..961950a21 100644
--- a/linux/drivers/media/video/zoran_procfs.c
+++ b/linux/drivers/media/video/zoran_procfs.c
@@ -162,10 +162,11 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer,
return -EFAULT;
}
string[count] = 0;
- dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n",
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n",
ZR_DEVNAME(zr), file->f_dentry->d_name.name, count, zr);
#else
+ dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n",
ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr);
#endif
ldelim = " \t\n";
diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c
index dbfdd6966..a2a632534 100644
--- a/linux/drivers/media/video/zr364xx.c
+++ b/linux/drivers/media/video/zr364xx.c
@@ -117,6 +117,7 @@ struct zr364xx_camera {
int height;
int method;
struct mutex lock;
+ int users;
};
@@ -642,25 +643,22 @@ static int zr364xx_open(struct inode *inode, struct file *file)
DBG("zr364xx_open");
- cam->skip = 2;
+ mutex_lock(&cam->lock);
- lock_kernel();
- err = video_exclusive_open(inode, file);
- if (err < 0) {
- unlock_kernel();
- return err;
+ if (cam->users) {
+ err = -EBUSY;
+ goto out;
}
if (!cam->framebuf) {
cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
if (!cam->framebuf) {
info("vmalloc_32 failed!");
- unlock_kernel();
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out;
}
}
- mutex_lock(&cam->lock);
for (i = 0; init[cam->method][i].size != -1; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -668,22 +666,23 @@ static int zr364xx_open(struct inode *inode, struct file *file)
init[cam->method][i].size);
if (err < 0) {
info("error during open sequence: %d", i);
- mutex_unlock(&cam->lock);
- unlock_kernel();
- return err;
+ goto out;
}
}
+ cam->skip = 2;
+ cam->users++;
file->private_data = vdev;
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
*/
mdelay(100);
+ err = 0;
+out:
mutex_unlock(&cam->lock);
- unlock_kernel();
- return 0;
+ return err;
}
@@ -704,6 +703,10 @@ static int zr364xx_release(struct inode *inode, struct file *file)
udev = cam->udev;
mutex_lock(&cam->lock);
+
+ cam->users--;
+ file->private_data = NULL;
+
for (i = 0; i < 2; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -711,21 +714,19 @@ static int zr364xx_release(struct inode *inode, struct file *file)
init[cam->method][i].size);
if (err < 0) {
info("error during release sequence");
- mutex_unlock(&cam->lock);
- return err;
+ goto out;
}
}
- file->private_data = NULL;
- video_exclusive_release(inode, file);
-
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
*/
mdelay(100);
+ err = 0;
+out:
mutex_unlock(&cam->lock);
- return 0;
+ return err;
}