diff options
Diffstat (limited to 'linux/drivers/media/video')
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, ¶m); + } 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(¶ms, ctrls->controls + i, cmd))) { + err = handle_ctrl(h->has_ac3, ¶ms, 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; } |