diff options
Diffstat (limited to 'linux/drivers/media/video')
94 files changed, 7816 insertions, 813 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 2dce16f86..47102c2c8 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -605,79 +605,7 @@ config VIDEO_STRADIS driver for PCI. There is a product page at <http://www.stradis.com/>. -config VIDEO_ZORAN - tristate "Zoran ZR36057/36067 Video For Linux" - depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS - help - Say Y for support for MJPEG capture cards based on the Zoran - 36057/36067 PCI controller chipset. This includes the Iomega - Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is - a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For - more information, check <file:Documentation/video4linux/Zoran>. - - To compile this driver as a module, choose M here: the - module will be called zr36067. - -config VIDEO_ZORAN_DC30 - tristate "Pinnacle/Miro DC30(+) support" - depends on VIDEO_ZORAN - select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback - card. This also supports really old DC10 cards based on the - zr36050 MJPEG codec and zr36016 VFE. - -config VIDEO_ZORAN_ZR36060 - tristate "Zoran ZR36060" - depends on VIDEO_ZORAN - help - Say Y to support Zoran boards based on 36060 chips. - This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 - and 33 R10 and AverMedia 6 boards. - -config VIDEO_ZORAN_BUZ - tristate "Iomega Buz support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Iomega Buz MJPEG capture/playback card. - -config VIDEO_ZORAN_DC10 - tristate "Pinnacle/Miro DC10(+) support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33 - tristate "Linux Media Labs LML33 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Linux Media Labs LML33 MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33R10 - tristate "Linux Media Labs LML33R10 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO - help - support for the Linux Media Labs LML33R10 MJPEG capture/playback - card. - -config VIDEO_ZORAN_AVS6EYES - tristate "AverMedia 6 Eyes support (EXPERIMENTAL)" - depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1 - select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the AverMedia 6 Eyes video surveillance card. +source "drivers/media/video/zoran/Kconfig" config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index bcd23e3cb..745780e1f 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -2,8 +2,6 @@ # Makefile for the video capture/playback device drivers. # -zr36067-objs := zoran_procfs.o zoran_device.o \ - zoran_driver.o zoran_card.o tuner-objs := tuner-core.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o @@ -55,9 +53,7 @@ obj-$(CONFIG_VIDEO_BT856) += bt856.o obj-$(CONFIG_VIDEO_BT866) += bt866.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o -obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o -obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o -obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o +obj-$(CONFIG_VIDEO_ZORAN) += zoran/ obj-$(CONFIG_VIDEO_PMS) += pms.o obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c index d8626e354..73f5141a4 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.c +++ b/linux/drivers/media/video/cx18/cx18-av-core.c @@ -42,6 +42,12 @@ int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) return 0; } +int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value) +{ + cx18_write_reg_noretry(cx, value, 0xc40000 + addr); + return 0; +} + u8 cx18_av_read(struct cx18 *cx, u16 addr) { u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3)); @@ -55,6 +61,11 @@ u32 cx18_av_read4(struct cx18 *cx, u16 addr) return cx18_read_reg(cx, 0xc40000 + addr); } +u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr) +{ + return cx18_read_reg_noretry(cx, 0xc40000 + addr); +} + int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, u8 or_value) { diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h index eb61fa1e0..b67d8df20 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.h +++ b/linux/drivers/media/video/cx18/cx18-av-core.h @@ -301,8 +301,10 @@ struct cx18_av_state { /* cx18_av-core.c */ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); +int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value); u8 cx18_av_read(struct cx18 *cx, u16 addr); u32 cx18_av_read4(struct cx18 *cx, u16 addr); +u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr); int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg); diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c index 0488b6297..522a035b2 100644 --- a/linux/drivers/media/video/cx18/cx18-av-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c @@ -50,7 +50,7 @@ int cx18_av_loadfw(struct cx18 *cx) cx18_av_write4(cx, 0x8100, 0x00010000); /* Put the 8051 in reset and enable firmware upload */ - cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000); ptr = fw->data; size = fw->size; @@ -59,22 +59,28 @@ int cx18_av_loadfw(struct cx18 *cx) u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); u32 value = 0; int retries2; + int unrec_err = 0; - for (retries2 = 0; retries2 < 5; retries2++) { - cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); + for (retries2 = 0; retries2 < CX18_MAX_MMIO_RETRIES; + retries2++) { + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, + dl_control); udelay(10); - value = cx18_av_read4(cx, CXADEC_DL_CTL); + value = cx18_av_read4_noretry(cx, + CXADEC_DL_CTL); if (value == dl_control) break; /* Check if we can correct the byte by changing the address. We can only write the lower address byte of the address. */ if ((value & 0x3F00) != (dl_control & 0x3F00)) { - retries2 = 5; + unrec_err = 1; break; } } - if (retries2 >= 5) + cx18_log_write_retries(cx, retries2, + cx->reg_mem + 0xc40000 + CXADEC_DL_CTL); + if (unrec_err || retries2 >= CX18_MAX_MMIO_RETRIES) break; } if (i == size) diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c index 3cb9734ec..7345fc09d 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.c +++ b/linux/drivers/media/video/cx18/cx18-cards.c @@ -292,12 +292,121 @@ static const struct cx18_card cx18_card_cnxt_raptor_pal = { /* ------------------------------------------------------------------------- */ +/* Toshiba Qosmio laptop internal DVB-T/Analog Hybrid Tuner */ + +static const struct cx18_card_pci_info cx18_pci_toshiba_qosmio_dvbt[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_TOSHIBA, 0x0110 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { + .type = CX18_CARD_TOSHIBA_QOSMIO_DVBT, + .name = "Toshiba Qosmio DVB-T/Analog", + .comment = "Experimenters and photos needed for device to work well.\n" + "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, +#if 0 + .hw_muxer = CX18_HW_GPIO, + .hw_all = CX18_HW_TUNER | CX18_HW_GPIO, +#endif + .hw_all = CX18_HW_TUNER, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .ddr = { + .chip_config = 0x202, + .refresh = 0x3bb, + .timing1 = 0x33320a63, + .timing2 = 0x0a, + .tune_lane = 0, + .initial_emrs = 0x42, + }, +#if 0 + .gpio_init.initial_value = 0x1, + .gpio_init.direction = 0x1, + .gpio_audio_input = { .mask = 0x1, + .tuner = 0x1, .linein = 0x0, .radio = 0x1 }, +#endif + .xceive_pin = 15, + .pci_list = cx18_pci_toshiba_qosmio_dvbt, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Leadtek WinFast PVR2100 */ + +static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_leadtek_pvr2100 = { + .type = CX18_CARD_LEADTEK_PVR2100, + .name = "Leadtek WinFast PVR2100", + .comment = "Experimenters and photos needed for device to work well.\n" + "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_GPIO, + .hw_all = CX18_HW_TUNER | CX18_HW_GPIO, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, + .ddr = { + /* + * Pointer to proper DDR config values provided by + * Terry Wu <terrywu at leadtek.com.tw> + */ + .chip_config = 0x303, + .refresh = 0x3bb, + .timing1 = 0x24220e83, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0x2, + }, + .gpio_init.initial_value = 0x6, + .gpio_init.direction = 0x7, + .gpio_audio_input = { .mask = 0x7, + .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, + .xceive_pin = 15, + .pci_list = cx18_pci_leadtek_pvr2100, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + static const struct cx18_card *cx18_card_list[] = { &cx18_card_hvr1600_esmt, &cx18_card_hvr1600_samsung, &cx18_card_h900, &cx18_card_mpc718, &cx18_card_cnxt_raptor_pal, + &cx18_card_toshiba_qosmio_dvbt, + &cx18_card_leadtek_pvr2100, }; const struct cx18_card *cx18_get_card(u16 index) diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 08b811615..085121c2b 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -96,6 +96,7 @@ static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; static int cx18_pci_latency = 1; +int cx18_retry_mmio = 1; int cx18_debug; module_param_array(tuner, int, &tuner_c, 0644); @@ -106,6 +107,7 @@ module_param_string(pal, pal, sizeof(pal), 0644); module_param_string(secam, secam, sizeof(secam), 0644); module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); module_param_named(debug, cx18_debug, int, 0644); +module_param_named(retry_mmio, cx18_retry_mmio, int, 0644); module_param(cx18_pci_latency, int, 0644); module_param(cx18_first_minor, int, 0644); @@ -128,6 +130,8 @@ MODULE_PARM_DESC(cardtype, "\t\t\t 3 = Compro VideoMate H900\n" "\t\t\t 4 = Yuan MPC718\n" "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" + "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" + "\t\t\t 7 = Leadtek WinFast PVR2100\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -147,6 +151,9 @@ MODULE_PARM_DESC(debug, MODULE_PARM_DESC(cx18_pci_latency, "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" "\t\t\tDefault: Yes"); +MODULE_PARM_DESC(retry_mmio, + "Check and retry memory mapped IO accesses\n" + "\t\t\tDefault: 1 [Yes]"); MODULE_PARM_DESC(mmio_ndelay, "Delay (ns) for each CX23418 memory mapped IO access.\n" "\t\t\tTry larger values that are close to a multiple of the\n" @@ -827,6 +834,7 @@ err: if (retval == 0) retval = -ENODEV; CX18_ERR("Error %d on initialization\n", retval); + cx18_log_statistics(cx); kfree(cx18_cards[cx18_cards_active]); cx18_cards[cx18_cards_active] = NULL; @@ -931,6 +939,7 @@ static void cx18_remove(struct pci_dev *pci_dev) pci_disable_device(cx->dev); + cx18_log_statistics(cx); CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); } diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 66cb74887..fa8be0731 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -79,7 +79,9 @@ #define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ #define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ #define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ -#define CX18_CARD_LAST 4 +#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/ +#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */ +#define CX18_CARD_LAST 6 #define CX18_ENC_STREAM_TYPE_MPG 0 #define CX18_ENC_STREAM_TYPE_TS 1 @@ -99,6 +101,8 @@ #define CX18_PCI_ID_COMPRO 0x185b #define CX18_PCI_ID_YUAN 0x12ab #define CX18_PCI_ID_CONEXANT 0x14f1 +#define CX18_PCI_ID_TOSHIBA 0x1179 +#define CX18_PCI_ID_LEADTEK 0x107D /* ======================================================================== */ /* ========================== START USER SETTABLE DMA VARIABLES =========== */ @@ -171,6 +175,7 @@ #define CX18_MAX_PGM_INDEX (400) +extern int cx18_retry_mmio; /* enable check & retry of mmio accesses */ extern int cx18_debug; @@ -344,6 +349,13 @@ struct cx18_i2c_algo_callback_data { int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ }; +#define CX18_MAX_MMIO_RETRIES 10 + +struct cx18_mmio_stats { + atomic_t retried_write[CX18_MAX_MMIO_RETRIES+1]; + atomic_t retried_read[CX18_MAX_MMIO_RETRIES+1]; +}; + /* Struct to hold info about cx18 cards */ struct cx18 { int num; /* board number, -1 during init! */ @@ -433,6 +445,9 @@ struct cx18 { u32 gpio_val; struct mutex gpio_lock; + /* Statistics */ + struct cx18_mmio_stats mmio_stats; + /* v4l2 and User settings */ /* codec settings */ diff --git a/linux/drivers/media/video/cx18/cx18-io.c b/linux/drivers/media/video/cx18/cx18-io.c index 55d1df932..700ab9439 100644 --- a/linux/drivers/media/video/cx18/cx18-io.c +++ b/linux/drivers/media/video/cx18/cx18-io.c @@ -24,6 +24,131 @@ #include "cx18-io.h" #include "cx18-irq.h" +void cx18_log_statistics(struct cx18 *cx) +{ + int i; + + if (!(cx18_debug & CX18_DBGFLG_INFO)) + return; + + for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++) + CX18_DEBUG_INFO("retried_write[%d] = %d\n", i, + atomic_read(&cx->mmio_stats.retried_write[i])); + for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++) + CX18_DEBUG_INFO("retried_read[%d] = %d\n", i, + atomic_read(&cx->mmio_stats.retried_read[i])); + return; +} + +void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_raw_writel_noretry(cx, val, addr); + if (val == cx18_raw_readl_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u32 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_raw_readl_noretry(cx, addr); + if (val != 0xffffffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u16 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_raw_readw_noretry(cx, addr); + if (val != 0xffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_writel_noretry(cx, val, addr); + if (val == cx18_readl_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_writew_noretry(cx, val, addr); + if (val == cx18_readw_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_writeb_noretry(cx, val, addr); + if (val == cx18_readb_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u32 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_readl_noretry(cx, addr); + if (val != 0xffffffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u16 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_readw_noretry(cx, addr); + if (val != 0xffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u8 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_readb_noretry(cx, addr); + if (val != 0xff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + void cx18_memcpy_fromio(struct cx18 *cx, void *to, const void __iomem *from, unsigned int len) { @@ -127,13 +252,3 @@ void cx18_setup_page(struct cx18 *cx, u32 addr) val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00); cx18_write_reg(cx, val, 0xD000F8); } - -/* Tries to recover from the CX23418 responding improperly on the PCI bus */ -int cx18_pci_try_recover(struct cx18 *cx) -{ - u16 status; - - pci_read_config_word(cx->dev, PCI_STATUS, &status); - pci_write_config_word(cx->dev, PCI_STATUS, status); - return 0; -} diff --git a/linux/drivers/media/video/cx18/cx18-io.h b/linux/drivers/media/video/cx18/cx18-io.h index 7ab7be253..197d4fbd9 100644 --- a/linux/drivers/media/video/cx18/cx18-io.h +++ b/linux/drivers/media/video/cx18/cx18-io.h @@ -31,102 +31,343 @@ static inline void cx18_io_delay(struct cx18 *cx) ndelay(cx->options.mmio_ndelay); } +/* + * Readback and retry of MMIO access for reliability: + * The concept was suggested by Steve Toth <stoth@linuxtv.org>. + * The implmentation is the fault of Andy Walls <awalls@radix.net>. + */ + +/* Statistics gathering */ +static inline +void cx18_log_write_retries(struct cx18 *cx, int i, const void *addr) +{ + if (i > CX18_MAX_MMIO_RETRIES) + i = CX18_MAX_MMIO_RETRIES; + atomic_inc(&cx->mmio_stats.retried_write[i]); + return; +} + +static inline +void cx18_log_read_retries(struct cx18 *cx, int i, const void *addr) +{ + if (i > CX18_MAX_MMIO_RETRIES) + i = CX18_MAX_MMIO_RETRIES; + atomic_inc(&cx->mmio_stats.retried_read[i]); + return; +} + +void cx18_log_statistics(struct cx18 *cx); + /* Non byteswapping memory mapped IO */ -static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr) +static inline +void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) { __raw_writel(val, addr); cx18_io_delay(cx); } -static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr) +void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr); + +static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_raw_writel_retry(cx, val, addr); + else + cx18_raw_writel_noretry(cx, val, addr); +} + + +static inline +u32 cx18_raw_readl_noretry(struct cx18 *cx, const void __iomem *addr) { u32 ret = __raw_readl(addr); cx18_io_delay(cx); return ret; } -static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr) +u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_raw_readl_retry(cx, addr); + + return cx18_raw_readl_noretry(cx, addr); +} + + +static inline +u16 cx18_raw_readw_noretry(struct cx18 *cx, const void __iomem *addr) { u16 ret = __raw_readw(addr); cx18_io_delay(cx); return ret; } +u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_raw_readw_retry(cx, addr); + + return cx18_raw_readw_noretry(cx, addr); +} + + /* Normal memory mapped IO */ -static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) +static inline +void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) { writel(val, addr); cx18_io_delay(cx); } -static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr) +void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr); + +static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_writel_retry(cx, val, addr); + else + cx18_writel_noretry(cx, val, addr); +} + + +static inline +void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr) { writew(val, addr); cx18_io_delay(cx); } -static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr) +void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr); + +static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_writew_retry(cx, val, addr); + else + cx18_writew_noretry(cx, val, addr); +} + + +static inline +void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr) { writeb(val, addr); cx18_io_delay(cx); } -static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr) +void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr); + +static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_writeb_retry(cx, val, addr); + else + cx18_writeb_noretry(cx, val, addr); +} + + +static inline u32 cx18_readl_noretry(struct cx18 *cx, const void __iomem *addr) { u32 ret = readl(addr); cx18_io_delay(cx); return ret; } -static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr) +u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_readl_retry(cx, addr); + + return cx18_readl_noretry(cx, addr); +} + + +static inline u16 cx18_readw_noretry(struct cx18 *cx, const void __iomem *addr) +{ + u16 ret = readw(addr); + cx18_io_delay(cx); + return ret; +} + +u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_readw_retry(cx, addr); + + return cx18_readw_noretry(cx, addr); +} + + +static inline u8 cx18_readb_noretry(struct cx18 *cx, const void __iomem *addr) { u8 ret = readb(addr); cx18_io_delay(cx); return ret; } +u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_readb_retry(cx, addr); + + return cx18_readb_noretry(cx, addr); +} + + +static inline +u32 cx18_write_sync_noretry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + cx18_writel_noretry(cx, val, addr); + return cx18_readl_noretry(cx, addr); +} + +static inline +u32 cx18_write_sync_retry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + cx18_writel_retry(cx, val, addr); + return cx18_readl_retry(cx, addr); +} + static inline u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr) { - cx18_writel(cx, val, addr); - return cx18_readl(cx, addr); + if (cx18_retry_mmio) + return cx18_write_sync_retry(cx, val, addr); + + return cx18_write_sync_noretry(cx, val, addr); } + void cx18_memcpy_fromio(struct cx18 *cx, void *to, const void __iomem *from, unsigned int len); void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); + /* Access "register" region of CX23418 memory mapped I/O */ +static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg) +{ + cx18_writel_noretry(cx, val, cx->reg_mem + reg); +} + +static inline void cx18_write_reg_retry(struct cx18 *cx, u32 val, u32 reg) +{ + cx18_writel_retry(cx, val, cx->reg_mem + reg); +} + static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg) { - cx18_writel(cx, val, cx->reg_mem + reg); + if (cx18_retry_mmio) + cx18_write_reg_retry(cx, val, reg); + else + cx18_write_reg_noretry(cx, val, reg); +} + + +static inline u32 cx18_read_reg_noretry(struct cx18 *cx, u32 reg) +{ + return cx18_readl_noretry(cx, cx->reg_mem + reg); +} + +static inline u32 cx18_read_reg_retry(struct cx18 *cx, u32 reg) +{ + return cx18_readl_retry(cx, cx->reg_mem + reg); } static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg) { - return cx18_readl(cx, cx->reg_mem + reg); + if (cx18_retry_mmio) + return cx18_read_reg_retry(cx, reg); + + return cx18_read_reg_noretry(cx, reg); +} + + +static inline u32 cx18_write_reg_sync_noretry(struct cx18 *cx, u32 val, u32 reg) +{ + return cx18_write_sync_noretry(cx, val, cx->reg_mem + reg); +} + +static inline u32 cx18_write_reg_sync_retry(struct cx18 *cx, u32 val, u32 reg) +{ + return cx18_write_sync_retry(cx, val, cx->reg_mem + reg); } static inline u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg) { - return cx18_write_sync(cx, val, cx->reg_mem + reg); + if (cx18_retry_mmio) + return cx18_write_reg_sync_retry(cx, val, reg); + + return cx18_write_reg_sync_noretry(cx, val, reg); } + /* Access "encoder memory" region of CX23418 memory mapped I/O */ +static inline void cx18_write_enc_noretry(struct cx18 *cx, u32 val, u32 addr) +{ + cx18_writel_noretry(cx, val, cx->enc_mem + addr); +} + +static inline void cx18_write_enc_retry(struct cx18 *cx, u32 val, u32 addr) +{ + cx18_writel_retry(cx, val, cx->enc_mem + addr); +} + static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr) { - cx18_writel(cx, val, cx->enc_mem + addr); + if (cx18_retry_mmio) + cx18_write_enc_retry(cx, val, addr); + else + cx18_write_enc_noretry(cx, val, addr); +} + + +static inline u32 cx18_read_enc_noretry(struct cx18 *cx, u32 addr) +{ + return cx18_readl_noretry(cx, cx->enc_mem + addr); +} + +static inline u32 cx18_read_enc_retry(struct cx18 *cx, u32 addr) +{ + return cx18_readl_retry(cx, cx->enc_mem + addr); } static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr) { - return cx18_readl(cx, cx->enc_mem + addr); + if (cx18_retry_mmio) + return cx18_read_enc_retry(cx, addr); + + return cx18_read_enc_noretry(cx, addr); +} + +static inline +u32 cx18_write_enc_sync_noretry(struct cx18 *cx, u32 val, u32 addr) +{ + return cx18_write_sync_noretry(cx, val, cx->enc_mem + addr); } -static inline u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr) +static inline +u32 cx18_write_enc_sync_retry(struct cx18 *cx, u32 val, u32 addr) { - return cx18_write_sync(cx, val, cx->enc_mem + addr); + return cx18_write_sync_retry(cx, val, cx->enc_mem + addr); } +static inline +u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr) +{ + if (cx18_retry_mmio) + return cx18_write_enc_sync_retry(cx, val, addr); + + return cx18_write_enc_sync_noretry(cx, val, addr); +} void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); @@ -134,7 +375,4 @@ void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); void cx18_sw2_irq_disable(struct cx18 *cx, u32 val); void cx18_setup_page(struct cx18 *cx, u32 addr); -/* Tries to recover from the CX23418 responding improperly on the PCI bus */ -int cx18_pci_try_recover(struct cx18 *cx); - #endif /* CX18_IO_H */ diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index b909c78d3..77fd0249e 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -857,6 +857,7 @@ static int cx18_log_status(struct file *file, void *fh) CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)cx->mpg_data_received, (long long)cx->vbi_data_inserted); + cx18_log_statistics(cx); CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); return 0; } diff --git a/linux/drivers/media/video/cx18/cx18-irq.c b/linux/drivers/media/video/cx18/cx18-irq.c index f117af782..85a56974b 100644 --- a/linux/drivers/media/video/cx18/cx18-irq.c +++ b/linux/drivers/media/video/cx18/cx18-irq.c @@ -49,8 +49,8 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) break; } if (i == CX18_MAX_STREAMS) { - CX18_WARN("DMA done for unknown handle %d for stream %s\n", - handle, s->name); + CX18_WARN("Got DMA done notification for unknown/inactive" + " handle %d\n", handle); mb->error = CXERR_NOT_OPEN; mb->cmd = 0; cx18_mb_ack(cx, mb); diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h index d5c7a6f96..9f6be2d45 100644 --- a/linux/drivers/media/video/cx18/cx18-version.h +++ b/linux/drivers/media/video/cx18/cx18-version.h @@ -25,7 +25,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 #define CX18_DRIVER_VERSION_MINOR 0 -#define CX18_DRIVER_VERSION_PATCHLEVEL 0 +#define CX18_DRIVER_VERSION_PATCHLEVEL 1 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ diff --git a/linux/drivers/media/video/dabusb.c b/linux/drivers/media/video/dabusb.c index 4acba6e92..21280dbc3 100644 --- a/linux/drivers/media/video/dabusb.c +++ b/linux/drivers/media/video/dabusb.c @@ -929,7 +929,8 @@ static int __init dabusb_init (void) dbg("dabusb_init: driver registered"); - info(DRIVER_VERSION ":" DRIVER_DESC); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); out: return retval; diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index 14ef4da24..d6856b331 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -127,10 +127,10 @@ static void em28xx_audio_isocirq(struct urb *urb) if (oldptr + length >= runtime->buffer_size) { unsigned int cnt = - runtime->buffer_size - oldptr - 1; + runtime->buffer_size - oldptr; memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride); - memcpy(runtime->dma_area, cp + cnt, + memcpy(runtime->dma_area, cp + cnt * stride, length * stride - cnt * stride); } else { memcpy(runtime->dma_area + oldptr * stride, cp, diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 38874e024..4f078da31 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -578,7 +578,7 @@ struct em28xx_board em28xx_boards[] = { }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, + .amux = 3, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, @@ -931,22 +931,23 @@ struct em28xx_board em28xx_boards[] = { }, [EM2880_BOARD_KWORLD_DVB_310U] = { .name = "KWorld DVB-T 310U", - .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, .tuner_type = TUNER_XC2028, + .has_dvb = 1, + .mts_firmware = 1, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { + .amux = EM28XX_AMUX_AC97_LINE_IN, + }, { /* S-video has not been tested yet */ .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, - .amux = 1, + .amux = EM28XX_AMUX_AC97_LINE_IN, } }, }, [EM2881_BOARD_DNT_DA2_HYBRID] = { @@ -1118,6 +1119,10 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2880_BOARD_KWORLD_DVB_305U }, { USB_DEVICE(0xeb1a, 0xe310), .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, +#if 0 + { USB_DEVICE(0xeb1a, 0xe310), + .driver_info = EM2880_BOARD_KWORLD_DVB_310U }, +#endif { USB_DEVICE(0xeb1a, 0xa316), .driver_info = EM2883_BOARD_KWORLD_HYBRID_A316 }, { USB_DEVICE(0xeb1a, 0xe320), @@ -1184,9 +1189,6 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, { USB_DEVICE(0x093b, 0xa005), .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, -#if 0 - EM2880_BOARD_KWORLD_DVB_310U }, -#endif { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -1264,6 +1266,7 @@ static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = { static struct em28xx_hash_table em28xx_eeprom_hash [] = { /* P/N: SA 60002070465 Tuner: TVF7533-MF */ {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, + {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028}, }; /* I2C devicelist hash table for devices with generic USB IDs */ @@ -1749,6 +1752,20 @@ void em28xx_card_setup(struct em28xx *dev) break; case EM2820_BOARD_UNKNOWN: case EM2800_BOARD_UNKNOWN: + /* + * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD. + * + * This occurs because they share identical USB vendor and + * product IDs. + * + * What we do here is look up the EEPROM hash of the K-WORLD + * and if it is found then we decide that we do not have + * a DIGIVOX and reset the device to the K-WORLD instead. + * + * This solution is only valid if they do not share eeprom + * hash identities which has not been determined as yet. + */ + case EM2880_BOARD_MSI_DIGIVOX_AD: if (!em28xx_hint_board(dev)) em28xx_set_model(dev); break; diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index 03c212e5a..b98749b8d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -452,6 +452,15 @@ static int dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2880_BOARD_KWORLD_DVB_310U: + dvb->frontend = dvb_attach(zl10353_attach, + &em28xx_zl10353_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" " isn't supported yet\n", diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig index 42b90742b..4d0817471 100644 --- a/linux/drivers/media/video/gspca/Kconfig +++ b/linux/drivers/media/video/gspca/Kconfig @@ -1,13 +1,212 @@ -config USB_GSPCA - tristate "USB GSPCA driver" +menuconfig USB_GSPCA + tristate "GSPCA based webcams" depends on VIDEO_V4L2 + default m ---help--- - Say Y here if you want support for various USB webcams. + Say Y here if you want to enable selecting webcams based + on the GSPCA framework. - See <file:Documentation/video4linux/gspca.txt> for more info. + See <file:Documentation/video4linux/gspca.txt> for more info. - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. - To compile this driver as modules, choose M here: the - modules will be called gspca_xxxx. + To compile this driver as modules, choose M here: the + modules will be called gspca_main. + + +if USB_GSPCA && VIDEO_V4L2 + +source "drivers/media/video/gspca/m5602/Kconfig" + +config USB_GSPCA_CONEX + tristate "Conexant Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Conexant chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_conex. + +config USB_GSPCA_ETOMS + tristate "Etoms USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Etoms chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_etoms. + +config USB_GSPCA_FINEPIX + tristate "Fujifilm FinePix USB V4L2 driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the FinePix chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_finepix. + +config USB_GSPCA_MARS + tristate "Mars USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Mars chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_mars. + +config USB_GSPCA_OV519 + tristate "OV519 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the OV519 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_ov519. + +config USB_GSPCA_PAC207 + tristate "Pixart PAC207 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the PAC207 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_pac207. + +config USB_GSPCA_PAC7311 + tristate "Pixart PAC7311 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the PAC7311 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_pac7311. + +config USB_GSPCA_SONIXB + tristate "SN9C102 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SONIXB chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_sonixb. + +config USB_GSPCA_SONIXJ + tristate "SONIX JPEG USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SONIXJ chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_sonixj + +config USB_GSPCA_SPCA500 + tristate "SPCA500 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA500 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca500. + +config USB_GSPCA_SPCA501 + tristate "SPCA501 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA501 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca501. + +config USB_GSPCA_SPCA505 + tristate "SPCA505 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA505 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca505. + +config USB_GSPCA_SPCA506 + tristate "SPCA506 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA506 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca506. + +config USB_GSPCA_SPCA508 + tristate "SPCA508 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA508 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca508. + +config USB_GSPCA_SPCA561 + tristate "SPCA561 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA561 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca561. + +config USB_GSPCA_STK014 + tristate "Syntek DV4000 (STK014) USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the STK014 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_stk014. + +config USB_GSPCA_SUNPLUS + tristate "SUNPLUS USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Sunplus + SPCA504(abc) SPCA533 SPCA536 chips. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca5xx. + +config USB_GSPCA_T613 + tristate "T613 (JPEG Compliance) USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the T613 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_t613. + +config USB_GSPCA_TV8532 + tristate "TV8532 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the TV8531 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_tv8532. + +config USB_GSPCA_VC032X + tristate "VC032X USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the VC032X chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_vc032x. + +config USB_GSPCA_ZC3XX + tristate "VC3xx USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the ZC3XX chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_zc3xx. + +endif diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile index e68a89652..22734f5a6 100644 --- a/linux/drivers/media/video/gspca/Makefile +++ b/linux/drivers/media/video/gspca/Makefile @@ -1,29 +1,48 @@ -obj-$(CONFIG_USB_GSPCA) += gspca_main.o \ - gspca_conex.o gspca_etoms.o gspca_mars.o \ - gspca_ov519.o gspca_pac207.o gspca_pac7311.o \ - gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \ - gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \ - gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \ - gspca_vc032x.o gspca_zc3xx.o +obj-$(CONFIG_USB_GSPCA) += gspca_main.o +obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o +obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o +obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o +obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o +obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o +obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o +obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o +obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o +obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o +obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o +obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o +obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o +obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o +obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o +obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o +obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o +obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o +obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o +obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o +obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o +obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o + +gspca_main-objs := gspca.o +gspca_conex-objs := conex.o +gspca_etoms-objs := etoms.o +gspca_finepix-objs := finepix.o +gspca_mars-objs := mars.o +gspca_ov519-objs := ov519.o +gspca_pac207-objs := pac207.o +gspca_pac7311-objs := pac7311.o +gspca_sonixb-objs := sonixb.o +gspca_sonixj-objs := sonixj.o +gspca_spca500-objs := spca500.o +gspca_spca501-objs := spca501.o +gspca_spca505-objs := spca505.o +gspca_spca506-objs := spca506.o +gspca_spca508-objs := spca508.o +gspca_spca561-objs := spca561.o +gspca_stk014-objs := stk014.o +gspca_sunplus-objs := sunplus.o +gspca_t613-objs := t613.o +gspca_tv8532-objs := tv8532.o +gspca_vc032x-objs := vc032x.o +gspca_zc3xx-objs := zc3xx.o + +obj-$(CONFIG_USB_M5602) += m5602/ -gspca_main-objs := gspca.o -gspca_conex-objs := conex.o -gspca_etoms-objs := etoms.o -gspca_mars-objs := mars.o -gspca_ov519-objs := ov519.o -gspca_pac207-objs := pac207.o -gspca_pac7311-objs := pac7311.o -gspca_sonixb-objs := sonixb.o -gspca_sonixj-objs := sonixj.o -gspca_spca500-objs := spca500.o -gspca_spca501-objs := spca501.o -gspca_spca505-objs := spca505.o -gspca_spca506-objs := spca506.o -gspca_spca508-objs := spca508.o -gspca_spca561-objs := spca561.o -gspca_stk014-objs := stk014.o -gspca_sunplus-objs := sunplus.o -gspca_t613-objs := t613.o -gspca_tv8532-objs := tv8532.o -gspca_vc032x-objs := vc032x.o -gspca_zc3xx-objs := zc3xx.o diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c index 4d9f4cc25..a9d51ba7c 100644 --- a/linux/drivers/media/video/gspca/conex.c +++ b/linux/drivers/media/video/gspca/conex.c @@ -837,12 +837,13 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { cx11646_initsize(gspca_dev); cx11646_fw(gspca_dev); cx_sensor(gspca_dev); cx11646_jpeg(gspca_dev); + return 0; } static void sd_stop0(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c index 86f3932c2..28869ef26 100644 --- a/linux/drivers/media/video/gspca/etoms.c +++ b/linux/drivers/media/video/gspca/etoms.c @@ -691,7 +691,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } /* -- start the camera -- */ -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -704,6 +704,7 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); et_video(gspca_dev, 1); /* video on */ + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c new file mode 100644 index 000000000..65d3cbfe6 --- /dev/null +++ b/linux/drivers/media/video/gspca/finepix.c @@ -0,0 +1,466 @@ +/* + * Fujifilm Finepix subdriver + * + * Copyright (C) 2008 Frank Zago + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "finepix" + +#include "gspca.h" + +MODULE_AUTHOR("Frank Zago <frank@zago.net>"); +MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver"); +MODULE_LICENSE("GPL"); + +/* Default timeout, in ms */ +#define FPIX_TIMEOUT (HZ / 10) + +/* Maximum transfer size to use. The windows driver reads by chunks of + * 0x2000 bytes, so do the same. Note: reading more seems to work + * too. */ +#define FPIX_MAX_TRANSFER 0x2000 + +/* Structure to hold all of our device specific stuff */ +struct usb_fpix { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + /* + * USB stuff + */ + struct usb_ctrlrequest ctrlreq; + struct urb *control_urb; + struct timer_list bulk_timer; + + enum { + FPIX_NOP, /* inactive, else streaming */ + FPIX_RESET, /* must reset */ + FPIX_REQ_FRAME, /* requesting a frame */ + FPIX_READ_FRAME, /* reading frame */ + } state; + + /* + * Driver stuff + */ + struct delayed_work wqe; + struct completion can_close; + int streaming; +}; + +/* Delay after which claim the next frame. If the delay is too small, + * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms + * will fail every 4 or 5 frames, but 30ms is perfect. */ +#define NEXT_FRAME_DELAY (((HZ * 30) + 999) / 1000) + +#define dev_new_state(new_state) { \ + PDEBUG(D_STREAM, "new state from %d to %d at %s:%d", \ + dev->state, new_state, __func__, __LINE__); \ + dev->state = new_state; \ +} + +/* These cameras only support 320x200. */ +static struct v4l2_pix_format fpix_mode[1] = { + { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0} +}; + +/* Reads part of a frame */ +static void read_frame_part(struct usb_fpix *dev) +{ + int ret; + + PDEBUG(D_STREAM, "read_frame_part"); + + /* Reads part of a frame */ + ret = usb_submit_urb(dev->gspca_dev.urb[0], GFP_ATOMIC); + if (ret) { + dev_new_state(FPIX_RESET); + schedule_delayed_work(&dev->wqe, 1); + PDEBUG(D_STREAM, "usb_submit_urb failed with %d", + ret); + } else { + /* Sometimes we never get a callback, so use a timer. + * Is this masking a bug somewhere else? */ + dev->bulk_timer.expires = jiffies + msecs_to_jiffies(150); + add_timer(&dev->bulk_timer); + } +} + +/* Callback for URBs. */ +static void urb_callback(struct urb *urb) +{ + struct gspca_dev *gspca_dev = urb->context; + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; + + PDEBUG(D_PACK, + "enter urb_callback - status=%d, length=%d", + urb->status, urb->actual_length); + + if (dev->state == FPIX_READ_FRAME) + del_timer(&dev->bulk_timer); + + if (urb->status != 0) { + /* We kill a stuck urb every 50 frames on average, so don't + * display a log message for that. */ + if (urb->status != -ECONNRESET) + PDEBUG(D_STREAM, "bad URB status %d", urb->status); + dev_new_state(FPIX_RESET); + schedule_delayed_work(&dev->wqe, 1); + } + + switch (dev->state) { + case FPIX_REQ_FRAME: + dev_new_state(FPIX_READ_FRAME); + read_frame_part(dev); + break; + + case FPIX_READ_FRAME: { + unsigned char *data = urb->transfer_buffer; + struct gspca_frame *frame; + + frame = gspca_get_i_frame(&dev->gspca_dev); + if (frame == NULL) + gspca_dev->last_packet_type = DISCARD_PACKET; + if (urb->actual_length < FPIX_MAX_TRANSFER || + (data[urb->actual_length-2] == 0xff && + data[urb->actual_length-1] == 0xd9)) { + + /* If the result is less than what was asked + * for, then it's the end of the + * frame. Sometime the jpeg is not complete, + * but there's nothing we can do. We also end + * here if the the jpeg ends right at the end + * of the frame. */ + if (frame) + gspca_frame_add(gspca_dev, LAST_PACKET, + frame, + data, urb->actual_length); + dev_new_state(FPIX_REQ_FRAME); + schedule_delayed_work(&dev->wqe, NEXT_FRAME_DELAY); + } else { + + /* got a partial image */ + if (frame) + gspca_frame_add(gspca_dev, + gspca_dev->last_packet_type + == LAST_PACKET + ? FIRST_PACKET : INTER_PACKET, + frame, + data, urb->actual_length); + read_frame_part(dev); + } + break; + } + + case FPIX_NOP: + case FPIX_RESET: + PDEBUG(D_STREAM, "invalid state %d", dev->state); + break; + } +} + +/* Request a new frame */ +static void request_frame(struct usb_fpix *dev) +{ + int ret; + struct gspca_dev *gspca_dev = &dev->gspca_dev; + + /* Setup command packet */ + memset(gspca_dev->usb_buf, 0, 12); + gspca_dev->usb_buf[0] = 0xd3; + gspca_dev->usb_buf[7] = 0x01; + + /* Request a frame */ + dev->ctrlreq.bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + dev->ctrlreq.bRequest = USB_REQ_GET_STATUS; + dev->ctrlreq.wValue = 0; + dev->ctrlreq.wIndex = 0; + dev->ctrlreq.wLength = cpu_to_le16(12); + + usb_fill_control_urb(dev->control_urb, + gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + (unsigned char *) &dev->ctrlreq, + gspca_dev->usb_buf, + 12, urb_callback, gspca_dev); + + ret = usb_submit_urb(dev->control_urb, GFP_ATOMIC); + if (ret) { + dev_new_state(FPIX_RESET); + schedule_delayed_work(&dev->wqe, 1); + PDEBUG(D_STREAM, "usb_submit_urb failed with %d", ret); + } +} + +/*--------------------------------------------------------------------------*/ + +/* State machine. */ +static void fpix_sm(struct work_struct *work) +{ + struct usb_fpix *dev = container_of(work, struct usb_fpix, wqe.work); + + PDEBUG(D_STREAM, "fpix_sm state %d", dev->state); + + /* verify that the device wasn't unplugged */ + if (!dev->gspca_dev.present) { + PDEBUG(D_STREAM, "device is gone"); + dev_new_state(FPIX_NOP); + complete(&dev->can_close); + return; + } + + if (!dev->streaming) { + PDEBUG(D_STREAM, "stopping state machine"); + dev_new_state(FPIX_NOP); + complete(&dev->can_close); + return; + } + + switch (dev->state) { + case FPIX_RESET: + dev_new_state(FPIX_REQ_FRAME); + schedule_delayed_work(&dev->wqe, HZ / 10); + break; + + case FPIX_REQ_FRAME: + /* get an image */ + request_frame(dev); + break; + + case FPIX_NOP: + case FPIX_READ_FRAME: + PDEBUG(D_STREAM, "invalid state %d", dev->state); + break; + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam = &gspca_dev->cam; + + cam->cam_mode = fpix_mode; + cam->nmodes = 1; + cam->epaddr = 0x01; /* todo: correct for all cams? */ + cam->bulk_size = FPIX_MAX_TRANSFER; + +/* gspca_dev->nbalt = 1; * use bulk transfer */ + return 0; +} + +/* Stop streaming and free the ressources allocated by sd_start. */ +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; + + dev->streaming = 0; + + /* Stop the state machine */ + if (dev->state != FPIX_NOP) + wait_for_completion(&dev->can_close); + + usb_free_urb(dev->control_urb); + dev->control_urb = NULL; +} + +/* Kill an URB that hasn't completed. */ +static void timeout_kill(unsigned long data) +{ + struct urb *urb = (struct urb *) data; + + usb_unlink_urb(urb); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; + + INIT_DELAYED_WORK(&dev->wqe, fpix_sm); + + init_timer(&dev->bulk_timer); + dev->bulk_timer.function = timeout_kill; + + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; + int ret; + int size_ret; + + /* Reset bulk in endpoint */ + usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr); + + /* Init the device */ + memset(gspca_dev->usb_buf, 0, 12); + gspca_dev->usb_buf[0] = 0xc6; + gspca_dev->usb_buf[8] = 0x20; + + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_GET_STATUS, + USB_DIR_OUT | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf, + 12, FPIX_TIMEOUT); + + if (ret != 12) { + PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret); + ret = -EIO; + goto error; + } + + /* Read the result of the command. Ignore the result, for it + * varies with the device. */ + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, + gspca_dev->cam.epaddr), + gspca_dev->usb_buf, FPIX_MAX_TRANSFER, &size_ret, + FPIX_TIMEOUT); + if (ret != 0) { + PDEBUG(D_STREAM, "usb_bulk_msg failed (%d)", ret); + ret = -EIO; + goto error; + } + + /* Request a frame, but don't read it */ + memset(gspca_dev->usb_buf, 0, 12); + gspca_dev->usb_buf[0] = 0xd3; + gspca_dev->usb_buf[7] = 0x01; + + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_GET_STATUS, + USB_DIR_OUT | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf, + 12, FPIX_TIMEOUT); + if (ret != 12) { + PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret); + ret = -EIO; + goto error; + } + + /* Again, reset bulk in endpoint */ + usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr); + + /* Allocate a control URB */ + dev->control_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->control_urb) { + PDEBUG(D_STREAM, "No free urbs available"); + ret = -EIO; + goto error; + } + + /* Various initializations. */ + init_completion(&dev->can_close); + dev->bulk_timer.data = (unsigned long)dev->gspca_dev.urb[0]; + dev->gspca_dev.urb[0]->complete = urb_callback; + dev->streaming = 1; + + /* Schedule a frame request. */ + dev_new_state(FPIX_REQ_FRAME); + schedule_delayed_work(&dev->wqe, 1); + + return 0; + +error: + /* Free the ressources */ + sd_stopN(gspca_dev); + return ret; +} + +/* Table of supported USB devices */ +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x04cb, 0x0104)}, + {USB_DEVICE(0x04cb, 0x0109)}, + {USB_DEVICE(0x04cb, 0x010b)}, + {USB_DEVICE(0x04cb, 0x010f)}, + {USB_DEVICE(0x04cb, 0x0111)}, + {USB_DEVICE(0x04cb, 0x0113)}, + {USB_DEVICE(0x04cb, 0x0115)}, + {USB_DEVICE(0x04cb, 0x0117)}, + {USB_DEVICE(0x04cb, 0x0119)}, + {USB_DEVICE(0x04cb, 0x011b)}, + {USB_DEVICE(0x04cb, 0x011d)}, + {USB_DEVICE(0x04cb, 0x0121)}, + {USB_DEVICE(0x04cb, 0x0123)}, + {USB_DEVICE(0x04cb, 0x0125)}, + {USB_DEVICE(0x04cb, 0x0127)}, + {USB_DEVICE(0x04cb, 0x0129)}, + {USB_DEVICE(0x04cb, 0x012b)}, + {USB_DEVICE(0x04cb, 0x012d)}, + {USB_DEVICE(0x04cb, 0x012f)}, + {USB_DEVICE(0x04cb, 0x0131)}, + {USB_DEVICE(0x04cb, 0x013b)}, + {USB_DEVICE(0x04cb, 0x013d)}, + {USB_DEVICE(0x04cb, 0x013f)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, + sizeof(struct usb_fpix), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "registered"); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index 8c98c7a05..c2ad862b6 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -29,6 +29,7 @@ #include <linux/string.h> #include <linux/pagemap.h> #include <linux/io.h> +#include <linux/kref.h> #include <asm/page.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) #include <asm/uaccess.h> @@ -106,6 +107,22 @@ static struct vm_operations_struct gspca_vm_ops = { .close = gspca_vm_close, }; +/* get the current input frame buffer */ +struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev) +{ + struct gspca_frame *frame; + int i; + + i = gspca_dev->fr_i; + i = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[i]; + if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) + != V4L2_BUF_FLAG_QUEUED) + return NULL; + return frame; +} +EXPORT_SYMBOL(gspca_get_i_frame); + /* * fill a video frame from an URB and resubmit */ @@ -114,7 +131,7 @@ static void fill_frame(struct gspca_dev *gspca_dev, { struct gspca_frame *frame; __u8 *data; /* address of data in the iso message */ - int i, j, len, st; + int i, len, st; cam_pkt_op pkt_scan; if (urb->status != 0) { @@ -128,11 +145,8 @@ static void fill_frame(struct gspca_dev *gspca_dev, for (i = 0; i < urb->number_of_packets; i++) { /* check the availability of the frame buffer */ - j = gspca_dev->fr_i; - j = gspca_dev->fr_queue[j]; - frame = &gspca_dev->frame[j]; - if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) - != V4L2_BUF_FLAG_QUEUED) { + frame = gspca_get_i_frame(gspca_dev); + if (!frame) { gspca_dev->last_packet_type = DISCARD_PACKET; break; } @@ -195,7 +209,6 @@ static void bulk_irq(struct urb *urb { struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; struct gspca_frame *frame; - int j; PDEBUG(D_PACK, "bulk irq"); if (!gspca_dev->streaming) @@ -209,11 +222,8 @@ static void bulk_irq(struct urb *urb } /* check the availability of the frame buffer */ - j = gspca_dev->fr_i; - j = gspca_dev->fr_queue[j]; - frame = &gspca_dev->frame[j]; - if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) - != V4L2_BUF_FLAG_QUEUED) { + frame = gspca_get_i_frame(gspca_dev); + if (!frame) { gspca_dev->last_packet_type = DISCARD_PACKET; } else { PDEBUG(D_PACK, "packet l:%d", urb->actual_length); @@ -237,7 +247,7 @@ static void bulk_irq(struct urb *urb * On LAST_PACKET, a new frame is returned. */ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, - int packet_type, + enum gspca_packet_type packet_type, struct gspca_frame *frame, const __u8 *data, int len) @@ -279,7 +289,7 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, } gspca_dev->last_packet_type = packet_type; - /* if last packet, wake the application and advance in the queue */ + /* if last packet, wake up the application and advance in the queue */ if (packet_type == LAST_PACKET) { frame->v4l2_buf.bytesused = frame->data_end - frame->data; frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED; @@ -317,7 +327,6 @@ static void *rvmalloc(unsigned long size) void *mem; unsigned long adr; -/* size = PAGE_ALIGN(size); (already done) */ mem = vmalloc_32(size); if (mem != NULL) { adr = (unsigned long) mem; @@ -421,7 +430,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) } /* - * search an input transfer endpoint in an alternate setting + * look for an input transfer endpoint in an alternate setting */ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, __u8 epaddr, @@ -445,7 +454,7 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, } /* - * search an input (isoc or bulk) endpoint + * look for an input (isoc or bulk) endpoint * * The endpoint is defined by the subdriver. * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). @@ -461,25 +470,34 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); ep = NULL; i = gspca_dev->alt; /* previous alt setting */ + + /* try isoc */ while (--i > 0) { /* alt 0 is unusable */ ep = alt_xfer(&intf->altsetting[i], gspca_dev->cam.epaddr, - gspca_dev->bulk - ? USB_ENDPOINT_XFER_BULK - : USB_ENDPOINT_XFER_ISOC); + USB_ENDPOINT_XFER_ISOC); if (ep) break; } + + /* if no isoc, try bulk */ if (ep == NULL) { - err("no transfer endpoint found"); - return NULL; + ep = alt_xfer(&intf->altsetting[0], + gspca_dev->cam.epaddr, + USB_ENDPOINT_XFER_BULK); + if (ep == NULL) { + err("no transfer endpoint found"); + return NULL; + } } PDEBUG(D_STREAM, "use alt %d ep 0x%02x", i, ep->desc.bEndpointAddress); - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); - if (ret < 0) { - err("set interface err %d", ret); - return NULL; + if (i > 0) { + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); + if (ret < 0) { + err("set interface err %d", ret); + return NULL; + } } gspca_dev->alt = i; /* memorize the current alt setting */ return ep; @@ -497,9 +515,10 @@ static int create_urbs(struct gspca_dev *gspca_dev, /* calculate the packet size and the number of packets */ psize = le16_to_cpu(ep->desc.wMaxPacketSize); - /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ - psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - if (!gspca_dev->bulk) { + if (gspca_dev->alt != 0) { /* isoc */ + + /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ + psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); npkt = ISO_MAX_SIZE / psize; if (npkt > ISO_MAX_PKT) npkt = ISO_MAX_PKT; @@ -508,9 +527,11 @@ static int create_urbs(struct gspca_dev *gspca_dev, "isoc %d pkts size %d = bsize:%d", npkt, psize, bsize); nurbs = DEF_NURBS; - } else { + } else { /* bulk */ npkt = 0; - bsize = psize; + bsize = gspca_dev->cam. bulk_size; + if (bsize == 0) + bsize = psize; PDEBUG(D_STREAM, "bulk bsize:%d", bsize); nurbs = 1; } @@ -542,7 +563,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, urb->pipe = usb_rcvisocpipe(gspca_dev->dev, ep->desc.bEndpointAddress); urb->transfer_flags = URB_ISO_ASAP - | URB_NO_TRANSFER_DMA_MAP; + | URB_NO_TRANSFER_DMA_MAP; urb->interval = ep->desc.bInterval; urb->complete = isoc_irq; urb->number_of_packets = npkt; @@ -553,6 +574,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, } else { /* bulk */ urb->pipe = usb_rcvbulkpipe(gspca_dev->dev, ep->desc.bEndpointAddress), + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->complete = bulk_irq; } } @@ -585,12 +607,16 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) goto out; /* start the cam */ - gspca_dev->sd_desc->start(gspca_dev); + ret = gspca_dev->sd_desc->start(gspca_dev); + if (ret < 0) { + destroy_urbs(gspca_dev); + goto out; + } gspca_dev->streaming = 1; atomic_set(&gspca_dev->nevent, 0); - /* start the bulk transfer is done by the subdriver */ - if (gspca_dev->bulk) + /* bulk transfers are started by the subdriver */ + if (gspca_dev->alt == 0) break; /* submit the URBs */ @@ -624,7 +650,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) return ret; } -/* Note both the queue and the usb lock should be hold when calling this */ +/* Note: both the queue and the usb locks should be held when calling this */ static void gspca_stream_off(struct gspca_dev *gspca_dev) { gspca_dev->streaming = 0; @@ -830,6 +856,16 @@ out: return ret; } +static void gspca_delete(struct kref *kref) +{ + struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref); + + PDEBUG(D_STREAM, "device deleted"); + + kfree(gspca_dev->usb_buf); + kfree(gspca_dev); +} + static int dev_open(struct inode *inode, struct file *file) { struct gspca_dev *gspca_dev; @@ -849,13 +885,19 @@ static int dev_open(struct inode *inode, struct file *file) goto out; } gspca_dev->users++; + + /* one more user */ + kref_get(&gspca_dev->kref); + file->private_data = gspca_dev; #ifdef GSPCA_DEBUG /* activate the v4l2 debug */ if (gspca_debug & D_V4L2) - gspca_dev->vdev.debug |= 3; + gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL + | V4L2_DEBUG_IOCTL_ARG; else - gspca_dev->vdev.debug &= ~3; + gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL + | V4L2_DEBUG_IOCTL_ARG); #endif ret = 0; out: @@ -889,7 +931,11 @@ static int dev_close(struct inode *inode, struct file *file) } file->private_data = NULL; mutex_unlock(&gspca_dev->queue_lock); + PDEBUG(D_STREAM, "close done"); + + kref_put(&gspca_dev->kref, gspca_delete); + return 0; } @@ -900,7 +946,6 @@ static int vidioc_querycap(struct file *file, void *priv, memset(cap, 0, sizeof *cap); strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); -/* strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); */ if (gspca_dev->dev->product != NULL) { strncpy(cap->card, gspca_dev->dev->product, sizeof cap->card); @@ -1534,7 +1579,6 @@ static int vidioc_qbuf(struct file *file, void *priv, } frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED; -/* frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */ if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) { frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr; @@ -1681,7 +1725,7 @@ static ssize_t dev_read(struct file *file, char __user *data, } /* if the process slept for more than 1 second, - * get anewer frame */ + * get a newer frame */ frame = &gspca_dev->frame[v4l2_buf.index]; if (--n < 0) break; /* avoid infinite loop */ @@ -1799,21 +1843,21 @@ int gspca_dev_probe(struct usb_interface *intf, if (dev_size < sizeof *gspca_dev) dev_size = sizeof *gspca_dev; gspca_dev = kzalloc(dev_size, GFP_KERNEL); - if (gspca_dev == NULL) { + if (!gspca_dev) { err("couldn't kzalloc gspca struct"); - return -EIO; + return -ENOMEM; } + kref_init(&gspca_dev->kref); gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); if (!gspca_dev->usb_buf) { err("out of memory"); - ret = -EIO; + ret = -ENOMEM; goto out; } gspca_dev->dev = dev; gspca_dev->iface = interface->bInterfaceNumber; gspca_dev->nbalt = intf->num_altsetting; gspca_dev->sd_desc = sd_desc; -/* gspca_dev->users = 0; (done by kzalloc) */ gspca_dev->nbufread = 2; /* configure the subdriver and initialize the USB device */ @@ -1852,8 +1896,7 @@ int gspca_dev_probe(struct usb_interface *intf, PDEBUG(D_PROBE, "probe ok"); return 0; out: - kfree(gspca_dev->usb_buf); - kfree(gspca_dev); + kref_put(&gspca_dev->kref, gspca_delete); return ret; } EXPORT_SYMBOL(gspca_dev_probe); @@ -1868,25 +1911,16 @@ void gspca_disconnect(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); - if (!gspca_dev) - return; - gspca_dev->present = 0; - mutex_lock(&gspca_dev->queue_lock); - mutex_lock(&gspca_dev->usb_lock); - gspca_dev->streaming = 0; - destroy_urbs(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - mutex_unlock(&gspca_dev->queue_lock); - while (gspca_dev->users != 0) { /* wait until fully closed */ - atomic_inc(&gspca_dev->nevent); - wake_up_interruptible(&gspca_dev->wq); /* wake processes */ - schedule(); - } + usb_set_intfdata(intf, NULL); + /* We don't want people trying to open up the device */ video_unregister_device(&gspca_dev->vdev); -/* Free the memory */ - kfree(gspca_dev->usb_buf); - kfree(gspca_dev); + + gspca_dev->present = 0; + gspca_dev->streaming = 0; + + kref_put(&gspca_dev->kref, gspca_delete); + PDEBUG(D_PROBE, "disconnect complete"); } EXPORT_SYMBOL(gspca_disconnect); diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 78a35a88c..4779dd0b0 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -56,6 +56,7 @@ extern int gspca_debug; /* device information - set at probe time */ struct cam { + int bulk_size; /* buffer size when image transfer by bulk */ struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; __u8 epaddr; @@ -93,7 +94,7 @@ struct sd_desc { /* mandatory operations */ cam_cf_op config; /* called on probe */ cam_op init; /* called on probe and resume */ - cam_v_op start; /* called on stream on */ + cam_op start; /* called on stream on */ cam_pkt_op pkt_scan; /* optional operations */ cam_v_op stopN; /* called on stream off - main alt */ @@ -105,10 +106,12 @@ struct sd_desc { }; /* packet types when moving from iso buf to frame buf */ -#define DISCARD_PACKET 0 -#define FIRST_PACKET 1 -#define INTER_PACKET 2 -#define LAST_PACKET 3 +enum gspca_packet_type { + DISCARD_PACKET, + FIRST_PACKET, + INTER_PACKET, + LAST_PACKET +}; struct gspca_frame { __u8 *data; /* frame buffer */ @@ -121,6 +124,7 @@ struct gspca_dev { struct video_device vdev; /* !! must be the first item */ struct file_operations fops; struct usb_device *dev; + struct kref kref; struct file *capt_file; /* file doing video capture */ struct cam cam; /* device information */ @@ -143,7 +147,6 @@ struct gspca_dev { __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ - __u8 bulk; /* image transfer by isoc (0) or bulk (1) */ __u8 curr_mode; /* current camera mode */ __u32 pixfmt; /* current mode parameters */ __u16 width; @@ -174,10 +177,11 @@ int gspca_dev_probe(struct usb_interface *intf, struct module *module); void gspca_disconnect(struct usb_interface *intf); struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, - int packet_type, + enum gspca_packet_type packet_type, struct gspca_frame *frame, const __u8 *data, int len); +struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev); #ifdef CONFIG_PM int gspca_suspend(struct usb_interface *intf, pm_message_t message); int gspca_resume(struct usb_interface *intf); diff --git a/linux/drivers/media/video/gspca/m5602/Kconfig b/linux/drivers/media/video/gspca/m5602/Kconfig new file mode 100644 index 000000000..5a69016ed --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/Kconfig @@ -0,0 +1,11 @@ +config USB_M5602 + tristate "ALi USB m5602 Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + ALi m5602 connected to various image sensors. + + See <file:Documentation/video4linux/m5602.txt> for more info. + + To compile this driver as a module, choose M here: the + module will be called gspca_m5602. diff --git a/linux/drivers/media/video/gspca/m5602/Makefile b/linux/drivers/media/video/gspca/m5602/Makefile new file mode 100644 index 000000000..226ab4fc9 --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_USB_M5602) += gspca_m5602.o + +gspca_m5602-objs := m5602_core.o \ + m5602_ov9650.o \ + m5602_mt9m111.o \ + m5602_po1030.o \ + m5602_s5k83a.o \ + m5602_s5k4aa.o + +EXTRA_CFLAGS += -Idrivers/media/video/gspca + diff --git a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h new file mode 100644 index 000000000..c786d7d3d --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h @@ -0,0 +1,170 @@ +/* + * USB Driver for ALi m5602 based webcams + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef M5602_BRIDGE_H_ +#define M5602_BRIDGE_H_ + +#include "gspca.h" + +#define MODULE_NAME "ALi m5602" + +/*****************************************************************************/ + +#undef PDEBUG +#undef info +#undef err + +#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \ + format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \ + format "\n" , ## arg) + +/* Debug parameters */ +#define DBG_INIT 0x1 +#define DBG_PROBE 0x2 +#define DBG_V4L2 0x4 +#define DBG_TRACE 0x8 +#define DBG_DATA 0x10 +#define DBG_V4L2_CID 0x20 +#define DBG_GSPCA 0x40 + +#define PDEBUG(level, fmt, args...) \ + do { \ + if (m5602_debug & level) \ + info("[%s:%d] " fmt, __func__, __LINE__ , \ + ## args); \ + } while (0) + +/*****************************************************************************/ + +#define M5602_XB_SENSOR_TYPE 0x00 +#define M5602_XB_SENSOR_CTRL 0x01 +#define M5602_XB_LINE_OF_FRAME_H 0x02 +#define M5602_XB_LINE_OF_FRAME_L 0x03 +#define M5602_XB_PIX_OF_LINE_H 0x04 +#define M5602_XB_PIX_OF_LINE_L 0x05 +#define M5602_XB_VSYNC_PARA 0x06 +#define M5602_XB_HSYNC_PARA 0x07 +#define M5602_XB_TEST_MODE_1 0x08 +#define M5602_XB_TEST_MODE_2 0x09 +#define M5602_XB_SIG_INI 0x0a +#define M5602_XB_DS_PARA 0x0e +#define M5602_XB_TRIG_PARA 0x0f +#define M5602_XB_CLK_PD 0x10 +#define M5602_XB_MCU_CLK_CTRL 0x12 +#define M5602_XB_MCU_CLK_DIV 0x13 +#define M5602_XB_SEN_CLK_CTRL 0x14 +#define M5602_XB_SEN_CLK_DIV 0x15 +#define M5602_XB_AUD_CLK_CTRL 0x16 +#define M5602_XB_AUD_CLK_DIV 0x17 +#define M5602_XB_DEVCTR1 0x41 +#define M5602_XB_EPSETR0 0x42 +#define M5602_XB_EPAFCTR 0x47 +#define M5602_XB_EPBFCTR 0x49 +#define M5602_XB_EPEFCTR 0x4f +#define M5602_XB_TEST_REG 0x53 +#define M5602_XB_ALT2SIZE 0x54 +#define M5602_XB_ALT3SIZE 0x55 +#define M5602_XB_OBSFRAME 0x56 +#define M5602_XB_PWR_CTL 0x59 +#define M5602_XB_ADC_CTRL 0x60 +#define M5602_XB_ADC_DATA 0x61 +#define M5602_XB_MISC_CTRL 0x62 +#define M5602_XB_SNAPSHOT 0x63 +#define M5602_XB_SCRATCH_1 0x64 +#define M5602_XB_SCRATCH_2 0x65 +#define M5602_XB_SCRATCH_3 0x66 +#define M5602_XB_SCRATCH_4 0x67 +#define M5602_XB_I2C_CTRL 0x68 +#define M5602_XB_I2C_CLK_DIV 0x69 +#define M5602_XB_I2C_DEV_ADDR 0x6a +#define M5602_XB_I2C_REG_ADDR 0x6b +#define M5602_XB_I2C_DATA 0x6c +#define M5602_XB_I2C_STATUS 0x6d +#define M5602_XB_GPIO_DAT_H 0x70 +#define M5602_XB_GPIO_DAT_L 0x71 +#define M5602_XB_GPIO_DIR_H 0x72 +#define M5602_XB_GPIO_DIR_L 0x73 +#define M5602_XB_GPIO_EN_H 0x74 +#define M5602_XB_GPIO_EN_L 0x75 +#define M5602_XB_GPIO_DAT 0x76 +#define M5602_XB_GPIO_DIR 0x77 +#define M5602_XB_MISC_CTL 0x70 + +#define I2C_BUSY 0x80 + +/*****************************************************************************/ + +/* Driver info */ +#define DRIVER_AUTHOR "ALi m5602 Linux Driver Project" +#define DRIVER_DESC "ALi m5602 webcam driver" + +#define M5602_ISOC_ENDPOINT_ADDR 0x81 +#define M5602_INTR_ENDPOINT_ADDR 0x82 + +#define M5602_MAX_FRAMES 32 +#define M5602_URBS 2 +#define M5602_ISOC_PACKETS 14 + +#define M5602_URB_TIMEOUT msecs_to_jiffies(2 * M5602_ISOC_PACKETS) +#define M5602_URB_MSG_TIMEOUT 5000 +#define M5602_FRAME_TIMEOUT 2 + +/*****************************************************************************/ + +/* A skeleton used for sending messages to the m5602 bridge */ +static const unsigned char bridge_urb_skeleton[] = { + 0x13, 0x00, 0x81, 0x00 +}; + +/* A skeleton used for sending messages to the sensor */ +static const unsigned char sensor_urb_skeleton[] = { + 0x23, M5602_XB_GPIO_EN_H, 0x81, 0x06, + 0x23, M5602_XB_MISC_CTRL, 0x81, 0x80, + 0x13, M5602_XB_I2C_DEV_ADDR, 0x81, 0x00, + 0x13, M5602_XB_I2C_REG_ADDR, 0x81, 0x00, + 0x13, M5602_XB_I2C_DATA, 0x81, 0x00, + 0x13, M5602_XB_I2C_CTRL, 0x81, 0x11 +}; + +/* m5602 device descriptor, currently it just wraps the m5602_camera struct */ +struct sd { + struct gspca_dev gspca_dev; + + /* The name of the m5602 camera */ + char *name; + + /* A pointer to the currently connected sensor */ + struct m5602_sensor *sensor; + + struct sd_desc *desc; + + /* The current frame's id, used to detect frame boundaries */ + u8 frame_id; + + /* The current frame count */ + u32 frame_count; +}; + +int m5602_read_bridge( + struct sd *sd, u8 address, u8 *i2c_data); + +int m5602_write_bridge( + struct sd *sd, u8 address, u8 i2c_data); + +#endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_core.c b/linux/drivers/media/video/gspca/m5602/m5602_core.c new file mode 100644 index 000000000..19d5e351c --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_core.c @@ -0,0 +1,313 @@ +/* + * USB Driver for ALi m5602 based webcams + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include "m5602_ov9650.h" +#include "m5602_mt9m111.h" +#include "m5602_po1030.h" +#include "m5602_s5k83a.h" +#include "m5602_s5k4aa.h" + +/* Kernel module parameters */ +int force_sensor; +int dump_bridge; +int dump_sensor; +unsigned int m5602_debug; + +static const __devinitdata struct usb_device_id m5602_table[] = { + {USB_DEVICE(0x0402, 0x5602)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, m5602_table); + +/* Reads a byte from the m5602 */ +int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x04, 0xc0, 0x14, + 0x8100 + address, buf, + 1, M5602_URB_MSG_TIMEOUT); + *i2c_data = buf[0]; + + PDEBUG(DBG_TRACE, "Reading bridge register 0x%x containing 0x%x", + address, *i2c_data); + + /* usb_control_msg(...) returns the number of bytes sent upon success, + mask that and return zero upon success instead*/ + return (err < 0) ? err : 0; +} + +/* Writes a byte to to the m5602 */ +int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + PDEBUG(DBG_TRACE, "Writing bridge register 0x%x with 0x%x", + address, i2c_data); + + memcpy(buf, bridge_urb_skeleton, + sizeof(bridge_urb_skeleton)); + buf[1] = address; + buf[3] = i2c_data; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 4, M5602_URB_MSG_TIMEOUT); + + /* usb_control_msg(...) returns the number of bytes sent upon success, + mask that and return zero upon success instead */ + return (err < 0) ? err : 0; +} + +/* Dump all the registers of the m5602 bridge, + unfortunately this breaks the camera until it's power cycled */ +static void m5602_dump_bridge(struct sd *sd) +{ + int i; + for (i = 0; i < 0x80; i++) { + unsigned char val = 0; + m5602_read_bridge(sd, i, &val); + info("ALi m5602 address 0x%x contains 0x%x", i, val); + } + info("Warning: The camera probably won't work until it's power cycled"); +} + +static int m5602_probe_sensor(struct sd *sd) +{ + /* Try the po1030 */ + sd->sensor = &po1030; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the mt9m111 sensor */ + sd->sensor = &mt9m111; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the s5k4aa */ + sd->sensor = &s5k4aa; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the ov9650 */ + sd->sensor = &ov9650; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the s5k83a */ + sd->sensor = &s5k83a; + if (!sd->sensor->probe(sd)) + return 0; + + /* More sensor probe function goes here */ + info("Failed to find a sensor"); + sd->sensor = NULL; + return -ENODEV; +} + +static int m5602_configure(struct gspca_dev *gspca_dev, + const struct usb_device_id *id); + +static int m5602_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + + PDEBUG(DBG_TRACE, "Initializing ALi m5602 webcam"); + /* Run the init sequence */ + err = sd->sensor->init(sd); + + return err; +} + +static int m5602_start_transfer(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* Send start command to the camera */ + const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01}; + memcpy(buf, buffer, sizeof(buffer)); + usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), + 0x04, 0x40, 0x19, 0x0000, buf, + 4, M5602_URB_MSG_TIMEOUT); + + PDEBUG(DBG_V4L2, "Transfer started"); + return 0; +} + +static void m5602_urb_complete(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, + __u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (len < 6) { + PDEBUG(DBG_DATA, "Packet is less than 6 bytes"); + return; + } + + /* Frame delimiter: ff xx xx xx ff ff */ + if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff && + data[2] != sd->frame_id) { + PDEBUG(DBG_DATA, "Frame delimiter detected"); + sd->frame_id = data[2]; + + /* Remove the extra fluff appended on each header */ + data += 6; + len -= 6; + + /* Complete the last frame (if any) */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, + frame, data, 0); + sd->frame_count++; + + /* Create a new frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); + + PDEBUG(DBG_V4L2, "Starting new frame %d", + sd->frame_count); + + } else { + int cur_frame_len = frame->data_end - frame->data; + + /* Remove urb header */ + data += 4; + len -= 4; + + if (cur_frame_len + len <= frame->v4l2_buf.length) { + PDEBUG(DBG_DATA, "Continuing frame %d copying %d bytes", + sd->frame_count, len); + + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, len); + } else if (frame->v4l2_buf.length - cur_frame_len > 0) { + /* Add the remaining data up to frame size */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, + frame->v4l2_buf.length - cur_frame_len); + } + } +} + +static void m5602_stop_transfer(struct gspca_dev *gspca_dev) +{ + /* Is there are a command to stop a data transfer? */ +} + +/* sub-driver description, the ctrl and nctrl is filled at probe time */ +static struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = m5602_configure, + .init = m5602_init, + .start = m5602_start_transfer, + .stopN = m5602_stop_transfer, + .pkt_scan = m5602_urb_complete +}; + +/* this function is called at probe time */ +static int m5602_configure(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + int err; + + PDEBUG(DBG_GSPCA, "m5602_configure start"); + + cam = &gspca_dev->cam; + cam->epaddr = M5602_ISOC_ENDPOINT_ADDR; + sd->desc = &sd_desc; + + if (dump_bridge) + m5602_dump_bridge(sd); + + /* Probe sensor */ + err = m5602_probe_sensor(sd); + if (err) + goto fail; + + PDEBUG(DBG_GSPCA, "m5602_configure end"); + return 0; + +fail: + PDEBUG(DBG_GSPCA, "m5602_configure failed"); + cam->cam_mode = NULL; + cam->nmodes = 0; + + return err; +} + +static int m5602_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = m5602_table, + .probe = m5602_probe, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif + .disconnect = gspca_disconnect +}; + +/* -- module insert / remove -- */ +static int __init mod_m5602_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "m5602 module registered"); + return 0; +} +static void __exit mod_m5602_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "m5602 module deregistered"); +} + +module_init(mod_m5602_init); +module_exit(mod_m5602_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +module_param_named(debug, m5602_debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "toggles debug on/off"); + +module_param(force_sensor, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(force_sensor, + "force detection of sensor, " + "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030"); + +module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); + +module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers " + "at startup providing a sensor is found"); diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c new file mode 100644 index 000000000..566d4925a --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c @@ -0,0 +1,345 @@ +/* + * Driver for the mt9m111 sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include "m5602_mt9m111.h" + +int mt9m111_probe(struct sd *sd) +{ + u8 data[2] = {0x00, 0x00}; + int i; + + if (force_sensor) { + if (force_sensor == MT9M111_SENSOR) { + info("Forcing a %s sensor", mt9m111.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + info("Probing for a mt9m111 sensor"); + + /* Do the preinit */ + for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { + if (preinit_mt9m111[i][0] == BRIDGE) { + m5602_write_bridge(sd, + preinit_mt9m111[i][1], + preinit_mt9m111[i][2]); + } else { + data[0] = preinit_mt9m111[i][2]; + data[1] = preinit_mt9m111[i][3]; + mt9m111_write_sensor(sd, + preinit_mt9m111[i][1], data, 2); + } + } + + if (mt9m111_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) + return -ENODEV; + + if ((data[0] == 0x14) && (data[1] == 0x3a)) { + info("Detected a mt9m111 sensor"); + goto sensor_found; + } + + return -ENODEV; + +sensor_found: + sd->gspca_dev.cam.cam_mode = mt9m111.modes; + sd->gspca_dev.cam.nmodes = mt9m111.nmodes; + sd->desc->ctrls = mt9m111.ctrls; + sd->desc->nctrls = mt9m111.nctrls; + return 0; +} + +int mt9m111_init(struct sd *sd) +{ + int i, err = 0; + + /* Init the sensor */ + for (i = 0; i < ARRAY_SIZE(init_mt9m111); i++) { + u8 data[2]; + + if (init_mt9m111[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + init_mt9m111[i][1], + init_mt9m111[i][2]); + } else { + data[0] = init_mt9m111[i][2]; + data[1] = init_mt9m111[i][3]; + err = mt9m111_write_sensor(sd, + init_mt9m111[i][1], data, 2); + } + } + + if (dump_sensor) + mt9m111_dump_registers(sd); + + return (err < 0) ? err : 0; +} + +int mt9m111_power_down(struct sd *sd) +{ + return 0; +} + +int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + + err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + data, 2); + *val = data[0] & MT9M111_RMB_MIRROR_ROWS; + PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val); + + return (err < 0) ? err : 0; +} + +int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val); + + /* Set the correct page map */ + err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + if (err < 0) + goto out; + + err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + if (err < 0) + goto out; + + data[0] = (data[0] & 0xfe) | val; + err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + data, 2); +out: + return (err < 0) ? err : 0; +} + +int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + + err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + data, 2); + *val = data[0] & MT9M111_RMB_MIRROR_COLS; + PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val); + + return (err < 0) ? err : 0; +} + +int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val); + + /* Set the correct page map */ + err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + if (err < 0) + goto out; + + err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + if (err < 0) + goto out; + + data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02); + err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + data, 2); +out: + return (err < 0) ? err : 0; +} + +int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err, tmp; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + + err = mt9m111_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2); + tmp = ((data[1] << 8) | data[0]); + + *val = ((tmp & (1 << 10)) * 2) | + ((tmp & (1 << 9)) * 2) | + ((tmp & (1 << 8)) * 2) | + (tmp & 0x7f); + + PDEBUG(DBG_V4L2_CID, "Read gain %d", *val); + + return (err < 0) ? err : 0; +} + +int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err, tmp; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + + /* Set the correct page map */ + err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + if (err < 0) + goto out; + + if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2) + return -EINVAL; + + if ((val >= INITIAL_MAX_GAIN * 2 * 2) && + (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2)) + tmp = (1 << 10) | (val << 9) | + (val << 8) | (val / 8); + else if ((val >= INITIAL_MAX_GAIN * 2) && + (val < INITIAL_MAX_GAIN * 2 * 2)) + tmp = (1 << 9) | (1 << 8) | (val / 4); + else if ((val >= INITIAL_MAX_GAIN) && + (val < INITIAL_MAX_GAIN * 2)) + tmp = (1 << 8) | (val / 2); + else + tmp = val; + + data[1] = (tmp & 0xff00) >> 8; + data[0] = (tmp & 0xff); + PDEBUG(DBG_V4L2_CID, "tmp=%d, data[1]=%d, data[0]=%d", tmp, + data[1], data[0]); + + err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, + data, 2); +out: + return (err < 0) ? err : 0; +} + +int mt9m111_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) { + int err, i; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, + sd->sensor->i2c_slave_id); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x1a); + if (err < 0) + goto out; + + for (i = 0; i < len && !err; i++) { + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); + + PDEBUG(DBG_TRACE, "Reading sensor register " + "0x%x contains 0x%x ", address, *i2c_data); + } +out: + return (err < 0) ? err : 0; +} + +int mt9m111_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + u8 *p; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* No sensor with a data width larger + than 16 bits has yet been seen, nor with 0 :p*/ + if (len > 2 || !len) + return -EINVAL; + + memcpy(buf, sensor_urb_skeleton, + sizeof(sensor_urb_skeleton)); + + buf[11] = sd->sensor->i2c_slave_id; + buf[15] = address; + + p = buf + 16; + + /* Copy a four byte write sequence for each byte to be written to */ + for (i = 0; i < len; i++) { + memcpy(p, sensor_urb_skeleton + 16, 4); + p[3] = i2c_data[i]; + p += 4; + PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x", + address, i2c_data[i]); + } + + /* Copy the tailer */ + memcpy(p, sensor_urb_skeleton + 20, 4); + + /* Set the total length */ + p[3] = 0x10 + len; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 20 + len * 4, M5602_URB_MSG_TIMEOUT); + + return (err < 0) ? err : 0; +} + +void mt9m111_dump_registers(struct sd *sd) +{ + u8 address, value[2] = {0x00, 0x00}; + + info("Dumping the mt9m111 register state"); + + info("Dumping the mt9m111 sensor core registers"); + value[1] = MT9M111_SENSOR_CORE; + mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + for (address = 0; address < 0xff; address++) { + mt9m111_read_sensor(sd, address, value, 2); + info("register 0x%x contains 0x%x%x", + address, value[0], value[1]); + } + + info("Dumping the mt9m111 color pipeline registers"); + value[1] = MT9M111_COLORPIPE; + mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + for (address = 0; address < 0xff; address++) { + mt9m111_read_sensor(sd, address, value, 2); + info("register 0x%x contains 0x%x%x", + address, value[0], value[1]); + } + + info("Dumping the mt9m111 camera control registers"); + value[1] = MT9M111_CAMERA_CONTROL; + mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + for (address = 0; address < 0xff; address++) { + mt9m111_read_sensor(sd, address, value, 2); + info("register 0x%x contains 0x%x%x", + address, value[0], value[1]); + } + + info("mt9m111 register state dump complete"); +} diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h new file mode 100644 index 000000000..79a5d8878 --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h @@ -0,0 +1,1020 @@ +/* + * Driver for the mt9m111 sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * Some defines taken from the mt9m111 sensor driver + * 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 as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef M5602_MT9M111_H_ +#define M5602_MT9M111_H_ + +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define MT9M111_SC_CHIPVER 0x00 +#define MT9M111_SC_ROWSTART 0x01 +#define MT9M111_SC_COLSTART 0x02 +#define MT9M111_SC_WINDOW_HEIGHT 0x03 +#define MT9M111_SC_WINDOW_WIDTH 0x04 +#define MT9M111_SC_HBLANK_CONTEXT_B 0x05 +#define MT9M111_SC_VBLANK_CONTEXT_B 0x06 +#define MT9M111_SC_HBLANK_CONTEXT_A 0x07 +#define MT9M111_SC_VBLANK_CONTEXT_A 0x08 +#define MT9M111_SC_SHUTTER_WIDTH 0x09 +#define MT9M111_SC_ROW_SPEED 0x0a + +#define MT9M111_SC_EXTRA_DELAY 0x0b +#define MT9M111_SC_SHUTTER_DELAY 0x0c +#define MT9M111_SC_RESET 0x0d +#define MT9M111_SC_R_MODE_CONTEXT_B 0x20 +#define MT9M111_SC_R_MODE_CONTEXT_A 0x21 +#define MT9M111_SC_FLASH_CONTROL 0x23 +#define MT9M111_SC_GREEN_1_GAIN 0x2b +#define MT9M111_SC_BLUE_GAIN 0x2c +#define MT9M111_SC_RED_GAIN 0x2d +#define MT9M111_SC_GREEN_2_GAIN 0x2e +#define MT9M111_SC_GLOBAL_GAIN 0x2f + +#define MT9M111_RMB_MIRROR_ROWS (1 << 0) +#define MT9M111_RMB_MIRROR_COLS (1 << 1) + +#define MT9M111_CONTEXT_CONTROL 0xc8 +#define MT9M111_PAGE_MAP 0xf0 +#define MT9M111_BYTEWISE_ADDRESS 0xf1 + +#define MT9M111_CP_OPERATING_MODE_CTL 0x06 +#define MT9M111_CP_LUMA_OFFSET 0x34 +#define MT9M111_CP_LUMA_CLIP 0x35 +#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A 0x3a +#define MT9M111_CP_LENS_CORRECTION_1 0x3b +#define MT9M111_CP_DEFECT_CORR_CONTEXT_A 0x4c +#define MT9M111_CP_DEFECT_CORR_CONTEXT_B 0x4d +#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B 0x9b +#define MT9M111_CP_GLOBAL_CLK_CONTROL 0xb3 + +#define MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18 0x65 +#define MT9M111_CC_AWB_PARAMETER_7 0x28 + +#define MT9M111_SENSOR_CORE 0x00 +#define MT9M111_COLORPIPE 0x01 +#define MT9M111_CAMERA_CONTROL 0x02 + +#define INITIAL_MAX_GAIN 64 +#define DEFAULT_GAIN 283 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; +extern unsigned int m5602_debug; + +int mt9m111_probe(struct sd *sd); +int mt9m111_init(struct sd *sd); +int mt9m111_power_down(struct sd *sd); + +int mt9m111_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +int mt9m111_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +void mt9m111_dump_registers(struct sd *sd); + +int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); + +static struct m5602_sensor mt9m111 = { + .name = "MT9M111", + + .i2c_slave_id = 0xba, + + .probe = mt9m111_probe, + .init = mt9m111_init, + .power_down = mt9m111_power_down, + + .read_sensor = mt9m111_read_sensor, + .write_sensor = mt9m111_write_sensor, + + .nctrls = 3, + .ctrls = { + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = mt9m111_set_vflip, + .get = mt9m111_get_vflip + }, { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = mt9m111_set_hflip, + .get = mt9m111_get_hflip + }, { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0, + .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, + .step = 1, + .default_value = DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_hflip, + .get = mt9m111_get_hflip + } + }, + + .nmodes = 1, + .modes = { + { + M5602_DEFAULT_FRAME_WIDTH, + M5602_DEFAULT_FRAME_HEIGHT, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT, + .bytesperline = M5602_DEFAULT_FRAME_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } + } +}; + +static const unsigned char preinit_mt9m111[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00} +}; + +static const unsigned char init_mt9m111[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0xff, 0xff}, + {SENSOR, MT9M111_SC_RESET, 0xff, 0xff}, + {SENSOR, MT9M111_SC_RESET, 0xff, 0xde}, + {SENSOR, MT9M111_SC_RESET, 0xff, 0xff}, + {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, + + {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0xff, 0xff}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, + {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, + {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, + {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, + + {SENSOR, 0xcd, 0x00, 0x0e}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, + {SENSOR, 0xd0, 0x00, 0x40}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, + {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {SENSOR, 0x33, 0x03, 0x49}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + + {SENSOR, 0x33, 0x03, 0x49}, + {SENSOR, 0x34, 0xc0, 0x19}, + {SENSOR, 0x3f, 0x20, 0x20}, + {SENSOR, 0x40, 0x20, 0x20}, + {SENSOR, 0x5a, 0xc0, 0x0a}, + {SENSOR, 0x70, 0x7b, 0x0a}, + {SENSOR, 0x71, 0xff, 0x00}, + {SENSOR, 0x72, 0x19, 0x0e}, + {SENSOR, 0x73, 0x18, 0x0f}, + {SENSOR, 0x74, 0x57, 0x32}, + {SENSOR, 0x75, 0x56, 0x34}, + {SENSOR, 0x76, 0x73, 0x35}, + {SENSOR, 0x77, 0x30, 0x12}, + {SENSOR, 0x78, 0x79, 0x02}, + {SENSOR, 0x79, 0x75, 0x06}, + {SENSOR, 0x7a, 0x77, 0x0a}, + {SENSOR, 0x7b, 0x78, 0x09}, + {SENSOR, 0x7c, 0x7d, 0x06}, + {SENSOR, 0x7d, 0x31, 0x10}, + {SENSOR, 0x7e, 0x00, 0x7e}, + {SENSOR, 0x80, 0x59, 0x04}, + {SENSOR, 0x81, 0x59, 0x04}, + {SENSOR, 0x82, 0x57, 0x0a}, + {SENSOR, 0x83, 0x58, 0x0b}, + {SENSOR, 0x84, 0x47, 0x0c}, + {SENSOR, 0x85, 0x48, 0x0e}, + {SENSOR, 0x86, 0x5b, 0x02}, + {SENSOR, 0x87, 0x00, 0x5c}, + {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, + {SENSOR, 0x60, 0x00, 0x80}, + {SENSOR, 0x61, 0x00, 0x00}, + {SENSOR, 0x62, 0x00, 0x00}, + {SENSOR, 0x63, 0x00, 0x00}, + {SENSOR, 0x64, 0x00, 0x00}, + + {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, + {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18}, + {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04}, + {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03}, + {SENSOR, 0x30, 0x04, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4}, + {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, + {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, + {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, + {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, + {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, + + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, + {SENSOR, 0xcd, 0x00, 0x0e}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, + {SENSOR, 0xd0, 0x00, 0x40}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, + {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {SENSOR, 0x33, 0x03, 0x49}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + + {SENSOR, 0x33, 0x03, 0x49}, + {SENSOR, 0x34, 0xc0, 0x19}, + {SENSOR, 0x3f, 0x20, 0x20}, + {SENSOR, 0x40, 0x20, 0x20}, + {SENSOR, 0x5a, 0xc0, 0x0a}, + {SENSOR, 0x70, 0x7b, 0x0a}, + {SENSOR, 0x71, 0xff, 0x00}, + {SENSOR, 0x72, 0x19, 0x0e}, + {SENSOR, 0x73, 0x18, 0x0f}, + {SENSOR, 0x74, 0x57, 0x32}, + {SENSOR, 0x75, 0x56, 0x34}, + {SENSOR, 0x76, 0x73, 0x35}, + {SENSOR, 0x77, 0x30, 0x12}, + {SENSOR, 0x78, 0x79, 0x02}, + {SENSOR, 0x79, 0x75, 0x06}, + {SENSOR, 0x7a, 0x77, 0x0a}, + {SENSOR, 0x7b, 0x78, 0x09}, + {SENSOR, 0x7c, 0x7d, 0x06}, + {SENSOR, 0x7d, 0x31, 0x10}, + {SENSOR, 0x7e, 0x00, 0x7e}, + {SENSOR, 0x80, 0x59, 0x04}, + {SENSOR, 0x81, 0x59, 0x04}, + {SENSOR, 0x82, 0x57, 0x0a}, + {SENSOR, 0x83, 0x58, 0x0b}, + {SENSOR, 0x84, 0x47, 0x0c}, + {SENSOR, 0x85, 0x48, 0x0e}, + {SENSOR, 0x86, 0x5b, 0x02}, + {SENSOR, 0x87, 0x00, 0x5c}, + {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, + {SENSOR, 0x60, 0x00, 0x80}, + {SENSOR, 0x61, 0x00, 0x00}, + {SENSOR, 0x62, 0x00, 0x00}, + {SENSOR, 0x63, 0x00, 0x00}, + {SENSOR, 0x64, 0x00, 0x00}, + + {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, + {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18}, + {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04}, + {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03}, + {SENSOR, 0x30, 0x04, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4}, + {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, + {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, + {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, + {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, + {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, + + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, + {SENSOR, 0xcd, 0x00, 0x0e}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, + {SENSOR, 0xd0, 0x00, 0x40}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, + {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {SENSOR, 0x33, 0x03, 0x49}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + + {SENSOR, 0x33, 0x03, 0x49}, + {SENSOR, 0x34, 0xc0, 0x19}, + {SENSOR, 0x3f, 0x20, 0x20}, + {SENSOR, 0x40, 0x20, 0x20}, + {SENSOR, 0x5a, 0xc0, 0x0a}, + {SENSOR, 0x70, 0x7b, 0x0a}, + {SENSOR, 0x71, 0xff, 0x00}, + {SENSOR, 0x72, 0x19, 0x0e}, + {SENSOR, 0x73, 0x18, 0x0f}, + {SENSOR, 0x74, 0x57, 0x32}, + {SENSOR, 0x75, 0x56, 0x34}, + {SENSOR, 0x76, 0x73, 0x35}, + {SENSOR, 0x77, 0x30, 0x12}, + {SENSOR, 0x78, 0x79, 0x02}, + {SENSOR, 0x79, 0x75, 0x06}, + {SENSOR, 0x7a, 0x77, 0x0a}, + {SENSOR, 0x7b, 0x78, 0x09}, + {SENSOR, 0x7c, 0x7d, 0x06}, + {SENSOR, 0x7d, 0x31, 0x10}, + {SENSOR, 0x7e, 0x00, 0x7e}, + {SENSOR, 0x80, 0x59, 0x04}, + {SENSOR, 0x81, 0x59, 0x04}, + {SENSOR, 0x82, 0x57, 0x0a}, + {SENSOR, 0x83, 0x58, 0x0b}, + {SENSOR, 0x84, 0x47, 0x0c}, + {SENSOR, 0x85, 0x48, 0x0e}, + {SENSOR, 0x86, 0x5b, 0x02}, + {SENSOR, 0x87, 0x00, 0x5c}, + {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, + {SENSOR, 0x60, 0x00, 0x80}, + {SENSOR, 0x61, 0x00, 0x00}, + {SENSOR, 0x62, 0x00, 0x00}, + {SENSOR, 0x63, 0x00, 0x00}, + {SENSOR, 0x64, 0x00, 0x00}, + + {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, + {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18}, + {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04}, + {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03}, + {SENSOR, 0x30, 0x04, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4}, + {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, + {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, + {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, + {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, + + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, 0xcd, 0x00, 0x0e}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, 0xd0, 0x00, 0x40}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, + {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, 0x33, 0x03, 0x49}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + + {SENSOR, 0x33, 0x03, 0x49}, + {SENSOR, 0x34, 0xc0, 0x19}, + {SENSOR, 0x3f, 0x20, 0x20}, + {SENSOR, 0x40, 0x20, 0x20}, + {SENSOR, 0x5a, 0xc0, 0x0a}, + {SENSOR, 0x70, 0x7b, 0x0a}, + {SENSOR, 0x71, 0xff, 0x00}, + {SENSOR, 0x72, 0x19, 0x0e}, + {SENSOR, 0x73, 0x18, 0x0f}, + {SENSOR, 0x74, 0x57, 0x32}, + {SENSOR, 0x75, 0x56, 0x34}, + {SENSOR, 0x76, 0x73, 0x35}, + {SENSOR, 0x77, 0x30, 0x12}, + {SENSOR, 0x78, 0x79, 0x02}, + {SENSOR, 0x79, 0x75, 0x06}, + {SENSOR, 0x7a, 0x77, 0x0a}, + {SENSOR, 0x7b, 0x78, 0x09}, + {SENSOR, 0x7c, 0x7d, 0x06}, + {SENSOR, 0x7d, 0x31, 0x10}, + {SENSOR, 0x7e, 0x00, 0x7e}, + {SENSOR, 0x80, 0x59, 0x04}, + {SENSOR, 0x81, 0x59, 0x04}, + {SENSOR, 0x82, 0x57, 0x0a}, + {SENSOR, 0x83, 0x58, 0x0b}, + {SENSOR, 0x84, 0x47, 0x0c}, + {SENSOR, 0x85, 0x48, 0x0e}, + {SENSOR, 0x86, 0x5b, 0x02}, + {SENSOR, 0x87, 0x00, 0x5c}, + {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, + {SENSOR, 0x60, 0x00, 0x80}, + {SENSOR, 0x61, 0x00, 0x00}, + {SENSOR, 0x62, 0x00, 0x00}, + {SENSOR, 0x63, 0x00, 0x00}, + {SENSOR, 0x64, 0x00, 0x00}, + {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, + {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, + {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, + {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, + {SENSOR, 0x30, 0x04, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe3, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90}, + {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xe6}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, + {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, + {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, + {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, + + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, 0xcd, 0x00, 0x0e}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, 0xd0, 0x00, 0x40}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, + {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + {SENSOR, 0x33, 0x03, 0x49}, + {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, + {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, + + {SENSOR, 0x33, 0x03, 0x49}, + {SENSOR, 0x34, 0xc0, 0x19}, + {SENSOR, 0x3f, 0x20, 0x20}, + {SENSOR, 0x40, 0x20, 0x20}, + {SENSOR, 0x5a, 0xc0, 0x0a}, + {SENSOR, 0x70, 0x7b, 0x0a}, + {SENSOR, 0x71, 0xff, 0x00}, + {SENSOR, 0x72, 0x19, 0x0e}, + {SENSOR, 0x73, 0x18, 0x0f}, + {SENSOR, 0x74, 0x57, 0x32}, + {SENSOR, 0x75, 0x56, 0x34}, + {SENSOR, 0x76, 0x73, 0x35}, + {SENSOR, 0x77, 0x30, 0x12}, + {SENSOR, 0x78, 0x79, 0x02}, + {SENSOR, 0x79, 0x75, 0x06}, + {SENSOR, 0x7a, 0x77, 0x0a}, + {SENSOR, 0x7b, 0x78, 0x09}, + {SENSOR, 0x7c, 0x7d, 0x06}, + {SENSOR, 0x7d, 0x31, 0x10}, + {SENSOR, 0x7e, 0x00, 0x7e}, + {SENSOR, 0x80, 0x59, 0x04}, + {SENSOR, 0x81, 0x59, 0x04}, + {SENSOR, 0x82, 0x57, 0x0a}, + {SENSOR, 0x83, 0x58, 0x0b}, + {SENSOR, 0x84, 0x47, 0x0c}, + {SENSOR, 0x85, 0x48, 0x0e}, + {SENSOR, 0x86, 0x5b, 0x02}, + {SENSOR, 0x87, 0x00, 0x5c}, + {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, + {SENSOR, 0x60, 0x00, 0x80}, + {SENSOR, 0x61, 0x00, 0x00}, + {SENSOR, 0x62, 0x00, 0x00}, + {SENSOR, 0x63, 0x00, 0x00}, + {SENSOR, 0x64, 0x00, 0x00}, + + {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, + {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, + {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, + {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f}, + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, + {SENSOR, 0x30, 0x04, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + /* Set number of blank rows chosen to 400 */ + {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90}, + /* Set the global gain to 283 (of 512) */ + {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x03, 0x63} +}; + +#endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c new file mode 100644 index 000000000..31c589625 --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -0,0 +1,546 @@ +/* + * Driver for the ov9650 sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include "m5602_ov9650.h" + +int ov9650_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + + /* The ov9650 registers have a max depth of one byte */ + if (len > 1 || !len) + return -EINVAL; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + + m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, + ov9650.i2c_slave_id); + m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); + m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len); + m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); + + for (i = 0; i < len; i++) { + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); + + PDEBUG(DBG_TRACE, "Reading sensor register " + "0x%x containing 0x%x ", address, *i2c_data); + } + return (err < 0) ? err : 0; +} + +int ov9650_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + u8 *p; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* The ov9650 only supports one byte writes */ + if (len > 1 || !len) + return -EINVAL; + + memcpy(buf, sensor_urb_skeleton, + sizeof(sensor_urb_skeleton)); + + buf[11] = sd->sensor->i2c_slave_id; + buf[15] = address; + + /* Special case larger sensor writes */ + p = buf + 16; + + /* Copy a four byte write sequence for each byte to be written to */ + for (i = 0; i < len; i++) { + memcpy(p, sensor_urb_skeleton + 16, 4); + p[3] = i2c_data[i]; + p += 4; + PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x", + address, i2c_data[i]); + } + + /* Copy the tailer */ + memcpy(p, sensor_urb_skeleton + 20, 4); + + /* Set the total length */ + p[3] = 0x10 + len; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 20 + len * 4, M5602_URB_MSG_TIMEOUT); + + return (err < 0) ? err : 0; +} + +int ov9650_probe(struct sd *sd) +{ + u8 prod_id = 0, ver_id = 0, i; + + if (force_sensor) { + if (force_sensor == OV9650_SENSOR) { + info("Forcing an %s sensor", ov9650.name); + goto sensor_found; + } + /* If we want to force another sensor, + don't try to probe this one */ + return -ENODEV; + } + + info("Probing for an ov9650 sensor"); + + /* Run the pre-init to actually probe the unit */ + for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) { + u8 data = preinit_ov9650[i][2]; + if (preinit_ov9650[i][0] == SENSOR) + ov9650_write_sensor(sd, + preinit_ov9650[i][1], &data, 1); + else + m5602_write_bridge(sd, preinit_ov9650[i][1], data); + } + + if (ov9650_read_sensor(sd, OV9650_PID, &prod_id, 1)) + return -ENODEV; + + if (ov9650_read_sensor(sd, OV9650_VER, &ver_id, 1)) + return -ENODEV; + + if ((prod_id == 0x96) && (ver_id == 0x52)) { + info("Detected an ov9650 sensor"); + goto sensor_found; + } + + return -ENODEV; + +sensor_found: + sd->gspca_dev.cam.cam_mode = ov9650.modes; + sd->gspca_dev.cam.nmodes = ov9650.nmodes; + sd->desc->ctrls = ov9650.ctrls; + sd->desc->nctrls = ov9650.nctrls; + return 0; +} + +int ov9650_init(struct sd *sd) +{ + int i, err = 0; + u8 data; + + if (dump_sensor) + ov9650_dump_registers(sd); + + for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) { + data = init_ov9650[i][2]; + if (init_ov9650[i][0] == SENSOR) + err = ov9650_write_sensor(sd, init_ov9650[i][1], + &data, 1); + else + err = m5602_write_bridge(sd, init_ov9650[i][1], data); + } + + if (!err && dmi_check_system(ov9650_flip_dmi_table)) { + info("vflip quirk active"); + data = 0x30; + err = ov9650_write_sensor(sd, OV9650_MVFP, &data, 1); + } + + return (err < 0) ? err : 0; +} + +int ov9650_power_down(struct sd *sd) +{ + int i; + for (i = 0; i < ARRAY_SIZE(power_down_ov9650); i++) { + u8 data = power_down_ov9650[i][2]; + if (power_down_ov9650[i][0] == SENSOR) + ov9650_write_sensor(sd, + power_down_ov9650[i][1], &data, 1); + else + m5602_write_bridge(sd, power_down_ov9650[i][1], data); + } + + return 0; +} + +int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + err = ov9650_read_sensor(sd, OV9650_COM1, &i2c_data, 1); + if (err < 0) + goto out; + *val = i2c_data & 0x03; + + err = ov9650_read_sensor(sd, OV9650_AECH, &i2c_data, 1); + if (err < 0) + goto out; + *val |= (i2c_data << 2); + + err = ov9650_read_sensor(sd, OV9650_AECHM, &i2c_data, 1); + if (err < 0) + goto out; + *val |= (i2c_data & 0x3f) << 10; + + PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val); +out: + return (err < 0) ? err : 0; +} + +int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + PDEBUG(DBG_V4L2_CID, "Set exposure to %d", + val & 0xffff); + + /* The 6 MSBs */ + i2c_data = (val >> 10) & 0x3f; + err = ov9650_write_sensor(sd, OV9650_AECHM, + &i2c_data, 1); + if (err < 0) + goto out; + + /* The 8 middle bits */ + i2c_data = (val >> 2) & 0xff; + err = ov9650_write_sensor(sd, OV9650_AECH, + &i2c_data, 1); + if (err < 0) + goto out; + + /* The 2 LSBs */ + i2c_data = val & 0x03; + err = ov9650_write_sensor(sd, OV9650_COM1, &i2c_data, 1); + +out: + return (err < 0) ? err : 0; +} + +int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + *val = (i2c_data & 0x03) << 8; + + err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); + *val |= i2c_data; + PDEBUG(DBG_V4L2_CID, "Read gain %d", *val); + return (err < 0) ? err : 0; +} + +int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + /* The 2 MSB */ + /* Read the OV9650_VREF register first to avoid + corrupting the VREF high and low bits */ + ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + /* Mask away all uninteresting bits */ + i2c_data = ((val & 0x0300) >> 2) | + (i2c_data & 0x3F); + err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1); + + /* The 8 LSBs */ + i2c_data = val & 0xff; + err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); + return (err < 0) ? err : 0; +} + +int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1); + *val = i2c_data; + + PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val); + + return (err < 0) ? err : 0; +} + +int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set red gain to %d", + val & 0xff); + + i2c_data = val & 0xff; + err = ov9650_write_sensor(sd, OV9650_RED, &i2c_data, 1); + + return (err < 0) ? err : 0; +} + +int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1); + *val = i2c_data; + + PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val); + + return (err < 0) ? err : 0; +} + +int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set blue gain to %d", + val & 0xff); + + i2c_data = val & 0xff; + err = ov9650_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); + + return (err < 0) ? err : 0; +} + +int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + if (dmi_check_system(ov9650_flip_dmi_table)) + *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1; + else + *val = (i2c_data & OV9650_HFLIP) >> 5; + PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val); + + return (err < 0) ? err : 0; +} + +int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val); + err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + if (err < 0) + goto out; + + if (dmi_check_system(ov9650_flip_dmi_table)) + i2c_data = ((i2c_data & 0xdf) | + (((val ? 0 : 1) & 0x01) << 5)); + else + i2c_data = ((i2c_data & 0xdf) | + ((val & 0x01) << 5)); + + err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); +out: + return (err < 0) ? err : 0; +} + +int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + if (dmi_check_system(ov9650_flip_dmi_table)) + *val = ((i2c_data & 0x10) >> 4) ? 0 : 1; + else + *val = (i2c_data & 0x10) >> 4; + PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val); + + return (err < 0) ? err : 0; +} + +int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val); + err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + if (err < 0) + goto out; + + if (dmi_check_system(ov9650_flip_dmi_table)) + i2c_data = ((i2c_data & 0xef) | + (((val ? 0 : 1) & 0x01) << 4)); + else + i2c_data = ((i2c_data & 0xef) | + ((val & 0x01) << 4)); + + err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); +out: + return (err < 0) ? err : 0; +} + +int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + if (err < 0) + goto out; + *val = (i2c_data & 0x03) << 8; + + err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); + *val |= i2c_data; + PDEBUG(DBG_V4L2_CID, "Read gain %d", *val); +out: + return (err < 0) ? err : 0; +} + +int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set gain to %d", val & 0x3ff); + + /* Read the OV9650_VREF register first to avoid + corrupting the VREF high and low bits */ + err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + if (err < 0) + goto out; + + /* Mask away all uninteresting bits */ + i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F); + err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1); + if (err < 0) + goto out; + + /* The 8 LSBs */ + i2c_data = val & 0xff; + err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); + +out: + return (err < 0) ? err : 0; +} + +int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + *val = (i2c_data & OV9650_AWB_EN) >> 1; + PDEBUG(DBG_V4L2_CID, "Read auto white balance %d", *val); + + return (err < 0) ? err : 0; +} + +int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set auto white balance to %d", val); + err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + if (err < 0) + goto out; + + i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); + err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1); +out: + return (err < 0) ? err : 0; +} + +int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + *val = (i2c_data & OV9650_AGC_EN) >> 2; + PDEBUG(DBG_V4L2_CID, "Read auto gain control %d", *val); + + return (err < 0) ? err : 0; +} + +int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(DBG_V4L2_CID, "Set auto gain control to %d", val); + err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + if (err < 0) + goto out; + + i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); + err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1); +out: + return (err < 0) ? err : 0; +} + +void ov9650_dump_registers(struct sd *sd) +{ + int address; + info("Dumping the ov9650 register state"); + for (address = 0; address < 0xa9; address++) { + u8 value; + ov9650_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + + info("ov9650 register state dump complete"); + + info("Probing for which registers that are read/write"); + for (address = 0; address < 0xff; address++) { + u8 old_value, ctrl_value; + u8 test_value[2] = {0xff, 0xff}; + + ov9650_read_sensor(sd, address, &old_value, 1); + ov9650_write_sensor(sd, address, test_value, 1); + ov9650_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value[0]) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + ov9650_write_sensor(sd, address, &old_value, 1); + } +} diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h new file mode 100644 index 000000000..fb21e7ffb --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h @@ -0,0 +1,505 @@ +/* + * Driver for the ov9650 sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef M5602_OV9650_H_ +#define M5602_OV9650_H_ + +#include <linux/dmi.h> + +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define OV9650_GAIN 0x00 +#define OV9650_BLUE 0x01 +#define OV9650_RED 0x02 +#define OV9650_VREF 0x03 +#define OV9650_COM1 0x04 +#define OV9650_BAVE 0x05 +#define OV9650_GEAVE 0x06 +#define OV9650_RSVD7 0x07 +#define OV9650_PID 0x0a +#define OV9650_VER 0x0b +#define OV9650_COM3 0x0c +#define OV9650_COM5 0x0e +#define OV9650_COM6 0x0f +#define OV9650_AECH 0x10 +#define OV9650_CLKRC 0x11 +#define OV9650_COM7 0x12 +#define OV9650_COM8 0x13 +#define OV9650_COM9 0x14 +#define OV9650_COM10 0x15 +#define OV9650_RSVD16 0x16 +#define OV9650_HSTART 0x17 +#define OV9650_HSTOP 0x18 +#define OV9650_VSTRT 0x19 +#define OV9650_VSTOP 0x1a +#define OV9650_PSHFT 0x1b +#define OV9650_MVFP 0x1e +#define OV9650_AEW 0x24 +#define OV9650_AEB 0x25 +#define OV9650_VPT 0x26 +#define OV9650_BBIAS 0x27 +#define OV9650_GbBIAS 0x28 +#define OV9650_Gr_COM 0x29 +#define OV9650_RBIAS 0x2c +#define OV9650_HREF 0x32 +#define OV9650_CHLF 0x33 +#define OV9650_ARBLM 0x34 +#define OV9650_RSVD35 0x35 +#define OV9650_RSVD36 0x36 +#define OV9650_ADC 0x37 +#define OV9650_ACOM38 0x38 +#define OV9650_OFON 0x39 +#define OV9650_TSLB 0x3a +#define OV9650_COM12 0x3c +#define OV9650_COM13 0x3d +#define OV9650_COM15 0x40 +#define OV9650_COM16 0x41 +#define OV9650_LCC1 0x62 +#define OV9650_LCC2 0x63 +#define OV9650_LCC3 0x64 +#define OV9650_LCC4 0x65 +#define OV9650_LCC5 0x66 +#define OV9650_HV 0x69 +#define OV9650_DBLV 0x6b +#define OV9650_COM21 0x8b +#define OV9650_COM22 0x8c +#define OV9650_COM24 0x8e +#define OV9650_DBLC1 0x8f +#define OV9650_RSVD94 0x94 +#define OV9650_RSVD95 0x95 +#define OV9650_RSVD96 0x96 +#define OV9650_LCCFB 0x9d +#define OV9650_LCCFR 0x9e +#define OV9650_AECHM 0xa1 +#define OV9650_COM26 0xa5 +#define OV9650_ACOMA8 0xa8 +#define OV9650_ACOMA9 0xa9 + +#define OV9650_REGISTER_RESET (1 << 7) +#define OV9650_VGA_SELECT (1 << 6) +#define OV9650_RGB_SELECT (1 << 2) +#define OV9650_RAW_RGB_SELECT (1 << 0) + +#define OV9650_FAST_AGC_AEC (1 << 7) +#define OV9650_AEC_UNLIM_STEP_SIZE (1 << 6) +#define OV9650_BANDING (1 << 5) +#define OV9650_AGC_EN (1 << 2) +#define OV9650_AWB_EN (1 << 1) +#define OV9650_AEC_EN (1 << 0) + +#define OV9650_VARIOPIXEL (1 << 2) +#define OV9650_SYSTEM_CLK_SEL (1 << 7) +#define OV9650_SLAM_MODE (1 << 4) + +#define OV9650_VFLIP (1 << 4) +#define OV9650_HFLIP (1 << 5) + +#define GAIN_DEFAULT 0x14 +#define RED_GAIN_DEFAULT 0x70 +#define BLUE_GAIN_DEFAULT 0x20 +#define EXPOSURE_DEFAULT 0x5003 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; +extern unsigned int m5602_debug; + +int ov9650_probe(struct sd *sd); +int ov9650_init(struct sd *sd); +int ov9650_power_down(struct sd *sd); + +int ov9650_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); +int ov9650_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +void ov9650_dump_registers(struct sd *sd); + +int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val); +int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); +int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); + +static struct m5602_sensor ov9650 = { + .name = "OV9650", + .i2c_slave_id = 0x60, + .probe = ov9650_probe, + .init = ov9650_init, + .power_down = ov9650_power_down, + .read_sensor = ov9650_read_sensor, + .write_sensor = ov9650_write_sensor, + + .nctrls = 8, + .ctrls = { + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0xffff, + .step = 0x1, + .default_value = EXPOSURE_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_exposure, + .get = ov9650_get_exposure + }, { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0x3ff, + .step = 0x1, + .default_value = GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_gain, + .get = ov9650_get_gain + }, { + { + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = RED_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_red_balance, + .get = ov9650_get_red_balance + }, { + { + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = BLUE_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_blue_balance, + .get = ov9650_get_blue_balance + }, { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov9650_set_hflip, + .get = ov9650_get_hflip + }, { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov9650_set_vflip, + .get = ov9650_get_vflip + }, { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov9650_set_auto_white_balance, + .get = ov9650_get_auto_white_balance + }, { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto gain control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov9650_set_auto_gain, + .get = ov9650_get_auto_gain + } + }, + + .nmodes = 1, + .modes = { + { + M5602_DEFAULT_FRAME_WIDTH, + M5602_DEFAULT_FRAME_HEIGHT, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT, + .bytesperline = M5602_DEFAULT_FRAME_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } + } +}; + +static const unsigned char preinit_ov9650[][3] = +{ + /* [INITCAM] */ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a}, + /* Reset chip */ + {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, + /* Enable double clock */ + {SENSOR, OV9650_CLKRC, 0x80}, + /* Do something out of spec with the power */ + {SENSOR, OV9650_OFON, 0x40} +}; + +static const unsigned char init_ov9650[][3] = +{ + /* [INITCAM] */ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a}, + /* Reset chip */ + {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, + /* Enable double clock */ + {SENSOR, OV9650_CLKRC, 0x80}, + /* Do something out of spec with the power */ + {SENSOR, OV9650_OFON, 0x40}, + + /* Set QQVGA */ + {SENSOR, OV9650_COM1, 0x20}, + /* Set fast AGC/AEC algorithm with unlimited step size */ + {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC | + OV9650_AEC_UNLIM_STEP_SIZE | + OV9650_AWB_EN | OV9650_AGC_EN}, + + {SENSOR, OV9650_CHLF, 0x10}, + {SENSOR, OV9650_ARBLM, 0xbf}, + {SENSOR, OV9650_ACOM38, 0x81}, + /* Turn off color matrix coefficient double option */ + {SENSOR, OV9650_COM16, 0x00}, + /* Enable color matrix for RGB/YUV, Delay Y channel, + set output Y/UV delay to 1 */ + {SENSOR, OV9650_COM13, 0x19}, + /* Enable digital BLC, Set output mode to U Y V Y */ + {SENSOR, OV9650_TSLB, 0x0c}, + /* Limit the AGC/AEC stable upper region */ + {SENSOR, OV9650_COM24, 0x00}, + /* Enable HREF and some out of spec things */ + {SENSOR, OV9650_COM12, 0x73}, + /* Set all DBLC offset signs to positive and + do some out of spec stuff */ + {SENSOR, OV9650_DBLC1, 0xdf}, + {SENSOR, OV9650_COM21, 0x06}, + {SENSOR, OV9650_RSVD35, 0x91}, + /* Necessary, no camera stream without it */ + {SENSOR, OV9650_RSVD16, 0x06}, + {SENSOR, OV9650_RSVD94, 0x99}, + {SENSOR, OV9650_RSVD95, 0x99}, + {SENSOR, OV9650_RSVD96, 0x04}, + /* Enable full range output */ + {SENSOR, OV9650_COM15, 0x0}, + /* Enable HREF at optical black, enable ADBLC bias, + enable ADBLC, reset timings at format change */ + {SENSOR, OV9650_COM6, 0x4b}, + /* Subtract 32 from the B channel bias */ + {SENSOR, OV9650_BBIAS, 0xa0}, + /* Subtract 32 from the Gb channel bias */ + {SENSOR, OV9650_GbBIAS, 0xa0}, + /* Do not bypass the analog BLC and to some out of spec stuff */ + {SENSOR, OV9650_Gr_COM, 0x00}, + /* Subtract 32 from the R channel bias */ + {SENSOR, OV9650_RBIAS, 0xa0}, + /* Subtract 32 from the R channel bias */ + {SENSOR, OV9650_RBIAS, 0x0}, + {SENSOR, OV9650_COM26, 0x80}, + {SENSOR, OV9650_ACOMA9, 0x98}, + /* Set the AGC/AEC stable region upper limit */ + {SENSOR, OV9650_AEW, 0x68}, + /* Set the AGC/AEC stable region lower limit */ + {SENSOR, OV9650_AEB, 0x5c}, + /* Set the high and low limit nibbles to 3 */ + {SENSOR, OV9650_VPT, 0xc3}, + /* Set the Automatic Gain Ceiling (AGC) to 128x, + drop VSYNC at frame drop, + limit exposure timing, + drop frame when the AEC step is larger than the exposure gap */ + {SENSOR, OV9650_COM9, 0x6e}, + /* Set VSYNC negative, Set RESET to SLHS (slave mode horizontal sync) + and set PWDN to SLVS (slave mode vertical sync) */ + {SENSOR, OV9650_COM10, 0x42}, + /* Set horizontal column start high to default value */ + {SENSOR, OV9650_HSTART, 0x1a}, + /* Set horizontal column end */ + {SENSOR, OV9650_HSTOP, 0xbf}, + /* Complementing register to the two writes above */ + {SENSOR, OV9650_HREF, 0xb2}, + /* Set vertical row start high bits */ + {SENSOR, OV9650_VSTRT, 0x02}, + /* Set vertical row end low bits */ + {SENSOR, OV9650_VSTOP, 0x7e}, + /* Set complementing vertical frame control */ + {SENSOR, OV9650_VREF, 0x10}, + /* Set raw RGB output format with VGA resolution */ + {SENSOR, OV9650_COM7, OV9650_VGA_SELECT | + OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT}, + {SENSOR, OV9650_ADC, 0x04}, + {SENSOR, OV9650_HV, 0x40}, + /* Enable denoise, and white-pixel erase */ + {SENSOR, OV9650_COM22, 0x23}, + + /* Set the high bits of the exposure value */ + {SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)}, + + /* Set the low bits of the exposure value */ + {SENSOR, OV9650_COM1, (EXPOSURE_DEFAULT & 0xff)}, + {SENSOR, OV9650_GAIN, GAIN_DEFAULT}, + {SENSOR, OV9650_BLUE, BLUE_GAIN_DEFAULT}, + {SENSOR, OV9650_RED, RED_GAIN_DEFAULT}, + + {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL}, + {SENSOR, OV9650_COM5, OV9650_SYSTEM_CLK_SEL}, + + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, + {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x09}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x5e}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0xde} +}; + +static const unsigned char power_down_ov9650[][3] = +{ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {SENSOR, OV9650_COM7, 0x80}, + {SENSOR, OV9650_OFON, 0xf4}, + {SENSOR, OV9650_MVFP, 0x80}, + {SENSOR, OV9650_DBLV, 0x3f}, + {SENSOR, OV9650_RSVD36, 0x49}, + {SENSOR, OV9650_COM7, 0x05}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0} +}; + +/* Vertically and horizontally flips the image if matched, needed for machines + where the sensor is mounted upside down */ +static +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + const +#endif + struct dmi_system_id ov9650_flip_dmi_table[] = { + { + .ident = "ASUS A6VC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") + } + }, + { + .ident = "ASUS A6VM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") + } + }, + { + .ident = "ASUS A6JC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") + } + }, + { + .ident = "ASUS A6Kt", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") + } + }, + { } +}; + +#endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c new file mode 100644 index 000000000..08c015bde --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c @@ -0,0 +1,336 @@ +/* + * Driver for the po1030 sensor + * + * Copyright (c) 2008 Erik Andren + * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include "m5602_po1030.h" + +int po1030_probe(struct sd *sd) +{ + u8 prod_id = 0, ver_id = 0, i; + + if (force_sensor) { + if (force_sensor == PO1030_SENSOR) { + info("Forcing a %s sensor", po1030.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + info("Probing for a po1030 sensor"); + + /* Run the pre-init to actually probe the unit */ + for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { + u8 data = preinit_po1030[i][2]; + if (preinit_po1030[i][0] == SENSOR) + po1030_write_sensor(sd, + preinit_po1030[i][1], &data, 1); + else + m5602_write_bridge(sd, preinit_po1030[i][1], data); + } + + if (po1030_read_sensor(sd, 0x3, &prod_id, 1)) + return -ENODEV; + + if (po1030_read_sensor(sd, 0x4, &ver_id, 1)) + return -ENODEV; + + if ((prod_id == 0x02) && (ver_id == 0xef)) { + info("Detected a po1030 sensor"); + goto sensor_found; + } + return -ENODEV; + +sensor_found: + sd->gspca_dev.cam.cam_mode = po1030.modes; + sd->gspca_dev.cam.nmodes = po1030.nmodes; + sd->desc->ctrls = po1030.ctrls; + sd->desc->nctrls = po1030.nctrls; + return 0; +} + +int po1030_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + + m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, + sd->sensor->i2c_slave_id); + m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); + m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len); + m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); + + for (i = 0; i < len; i++) { + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); + + PDEBUG(DBG_TRACE, "Reading sensor register " + "0x%x containing 0x%x ", address, *i2c_data); + } + return (err < 0) ? err : 0; +} + +int po1030_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + u8 *p; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* The po1030 only supports one byte writes */ + if (len > 1 || !len) + return -EINVAL; + + memcpy(buf, sensor_urb_skeleton, sizeof(sensor_urb_skeleton)); + + buf[11] = sd->sensor->i2c_slave_id; + buf[15] = address; + + p = buf + 16; + + /* Copy a four byte write sequence for each byte to be written to */ + for (i = 0; i < len; i++) { + memcpy(p, sensor_urb_skeleton + 16, 4); + p[3] = i2c_data[i]; + p += 4; + PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x", + address, i2c_data[i]); + } + + /* Copy the footer */ + memcpy(p, sensor_urb_skeleton + 20, 4); + + /* Set the total length */ + p[3] = 0x10 + len; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 20 + len * 4, M5602_URB_MSG_TIMEOUT); + + return (err < 0) ? err : 0; +} + +int po1030_init(struct sd *sd) +{ + int i, err = 0; + + /* Init the sensor */ + for (i = 0; i < ARRAY_SIZE(init_po1030); i++) { + u8 data[2] = {0x00, 0x00}; + + switch (init_po1030[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + init_po1030[i][1], + init_po1030[i][2]); + break; + + case SENSOR: + data[0] = init_po1030[i][2]; + err = po1030_write_sensor(sd, + init_po1030[i][1], data, 1); + break; + + case SENSOR_LONG: + data[0] = init_po1030[i][2]; + data[1] = init_po1030[i][3]; + err = po1030_write_sensor(sd, + init_po1030[i][1], data, 2); + break; + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + + if (dump_sensor) + po1030_dump_registers(sd); + + return (err < 0) ? err : 0; +} + +int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_H, + &i2c_data, 1); + if (err < 0) + goto out; + *val = (i2c_data << 8); + + err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_M, + &i2c_data, 1); + *val |= i2c_data; + + PDEBUG(DBG_V4L2_CID, "Exposure read as %d", *val); +out: + return (err < 0) ? err : 0; +} + +int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + PDEBUG(DBG_V4L2, "Set exposure to %d", val & 0xffff); + + i2c_data = ((val & 0xff00) >> 8); + PDEBUG(DBG_V4L2, "Set exposure to high byte to 0x%x", + i2c_data); + + err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H, + &i2c_data, 1); + if (err < 0) + goto out; + + i2c_data = (val & 0xff); + PDEBUG(DBG_V4L2, "Set exposure to low byte to 0x%x", + i2c_data); + err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M, + &i2c_data, 1); + +out: + return (err < 0) ? err : 0; +} + +int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN, + &i2c_data, 1); + *val = i2c_data; + PDEBUG(DBG_V4L2_CID, "Read global gain %d", *val); + + return (err < 0) ? err : 0; +} + +int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + i2c_data = val & 0xff; + PDEBUG(DBG_V4L2, "Set global gain to %d", i2c_data); + err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN, + &i2c_data, 1); + return (err < 0) ? err : 0; +} + +int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN, + &i2c_data, 1); + *val = i2c_data; + PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val); + return (err < 0) ? err : 0; +} + +int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + i2c_data = val & 0xff; + PDEBUG(DBG_V4L2, "Set red gain to %d", i2c_data); + err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN, + &i2c_data, 1); + return (err < 0) ? err : 0; +} + +int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + + err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN, + &i2c_data, 1); + *val = i2c_data; + PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val); + + return (err < 0) ? err : 0; +} + +int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 i2c_data; + int err; + i2c_data = val & 0xff; + PDEBUG(DBG_V4L2, "Set blue gain to %d", i2c_data); + err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN, + &i2c_data, 1); + + return (err < 0) ? err : 0; +} + +int po1030_power_down(struct sd *sd) +{ + return 0; +} + +void po1030_dump_registers(struct sd *sd) +{ + int address; + u8 value = 0; + + info("Dumping the po1030 sensor core registers"); + for (address = 0; address < 0x7f; address++) { + po1030_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + + info("po1030 register state dump complete"); + + info("Probing for which registers that are read/write"); + for (address = 0; address < 0xff; address++) { + u8 old_value, ctrl_value; + u8 test_value[2] = {0xff, 0xff}; + + po1030_read_sensor(sd, address, &old_value, 1); + po1030_write_sensor(sd, address, test_value, 1); + po1030_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value[0]) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + po1030_write_sensor(sd, address, &old_value, 1); + } +} diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.h b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h new file mode 100644 index 000000000..68f34c97b --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h @@ -0,0 +1,478 @@ +/* + * Driver for the po1030 sensor. + * This is probably a pixel plus sensor but we haven't identified it yet + * + * Copyright (c) 2008 Erik Andren + * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * Register defines taken from Pascal Stangs Proxycon Armlib + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef M5602_PO1030_H_ +#define M5602_PO1030_H_ + +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define PO1030_REG_DEVID_H 0x00 +#define PO1030_REG_DEVID_L 0x01 +#define PO1030_REG_FRAMEWIDTH_H 0x04 +#define PO1030_REG_FRAMEWIDTH_L 0x05 +#define PO1030_REG_FRAMEHEIGHT_H 0x06 +#define PO1030_REG_FRAMEHEIGHT_L 0x07 +#define PO1030_REG_WINDOWX_H 0x08 +#define PO1030_REG_WINDOWX_L 0x09 +#define PO1030_REG_WINDOWY_H 0x0a +#define PO1030_REG_WINDOWY_L 0x0b +#define PO1030_REG_WINDOWWIDTH_H 0x0c +#define PO1030_REG_WINDOWWIDTH_L 0x0d +#define PO1030_REG_WINDOWHEIGHT_H 0x0e +#define PO1030_REG_WINDOWHEIGHT_L 0x0f + +#define PO1030_REG_GLOBALIBIAS 0x12 +#define PO1030_REG_PIXELIBIAS 0x13 + +#define PO1030_REG_GLOBALGAIN 0x15 +#define PO1030_REG_RED_GAIN 0x16 +#define PO1030_REG_GREEN_1_GAIN 0x17 +#define PO1030_REG_BLUE_GAIN 0x18 +#define PO1030_REG_GREEN_2_GAIN 0x19 + +#define PO1030_REG_INTEGLINES_H 0x1a +#define PO1030_REG_INTEGLINES_M 0x1b +#define PO1030_REG_INTEGLINES_L 0x1c + +#define PO1030_REG_CONTROL1 0x1d +#define PO1030_REG_CONTROL2 0x1e +#define PO1030_REG_CONTROL3 0x1f +#define PO1030_REG_CONTROL4 0x20 + +#define PO1030_REG_PERIOD50_H 0x23 +#define PO1030_REG_PERIOD50_L 0x24 +#define PO1030_REG_PERIOD60_H 0x25 +#define PO1030_REG_PERIOD60_L 0x26 +#define PO1030_REG_REGCLK167 0x27 +#define PO1030_REG_DELTA50 0x28 +#define PO1030_REG_DELTA60 0x29 + +#define PO1030_REG_ADCOFFSET 0x2c + +/* Gamma Correction Coeffs */ +#define PO1030_REG_GC0 0x2d +#define PO1030_REG_GC1 0x2e +#define PO1030_REG_GC2 0x2f +#define PO1030_REG_GC3 0x30 +#define PO1030_REG_GC4 0x31 +#define PO1030_REG_GC5 0x32 +#define PO1030_REG_GC6 0x33 +#define PO1030_REG_GC7 0x34 + +/* Color Transform Matrix */ +#define PO1030_REG_CT0 0x35 +#define PO1030_REG_CT1 0x36 +#define PO1030_REG_CT2 0x37 +#define PO1030_REG_CT3 0x38 +#define PO1030_REG_CT4 0x39 +#define PO1030_REG_CT5 0x3a +#define PO1030_REG_CT6 0x3b +#define PO1030_REG_CT7 0x3c +#define PO1030_REG_CT8 0x3d + +#define PO1030_REG_AUTOCTRL1 0x3e +#define PO1030_REG_AUTOCTRL2 0x3f + +#define PO1030_REG_YTARGET 0x40 +#define PO1030_REG_GLOBALGAINMIN 0x41 +#define PO1030_REG_GLOBALGAINMAX 0x42 + +/* Output format control */ +#define PO1030_REG_OUTFORMCTRL1 0x5a +#define PO1030_REG_OUTFORMCTRL2 0x5b +#define PO1030_REG_OUTFORMCTRL3 0x5c +#define PO1030_REG_OUTFORMCTRL4 0x5d +#define PO1030_REG_OUTFORMCTRL5 0x5e + +/* Imaging coefficients */ +#define PO1030_REG_YBRIGHT 0x73 +#define PO1030_REG_YCONTRAST 0x74 +#define PO1030_REG_YSATURATION 0x75 + +/*****************************************************************************/ + +#define PO1030_GLOBAL_GAIN_DEFAULT 0x12 +#define PO1030_EXPOSURE_DEFAULT 0xf0ff +#define PO1030_BLUE_GAIN_DEFAULT 0x40 +#define PO1030_RED_GAIN_DEFAULT 0x40 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; +extern unsigned int m5602_debug; + +int po1030_probe(struct sd *sd); +int po1030_init(struct sd *sd); +int po1030_power_down(struct sd *sd); + +void po1030_dump_registers(struct sd *sd); + +int po1030_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); +int po1030_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); +int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); + +static struct m5602_sensor po1030 = { + .name = "PO1030", + + .i2c_slave_id = 0xdc, + + .probe = po1030_probe, + .init = po1030_init, + .power_down = po1030_power_down, + + .nctrls = 4, + .ctrls = { + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_GLOBAL_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_gain, + .get = po1030_get_gain + }, { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0xffff, + .step = 0x1, + .default_value = PO1030_EXPOSURE_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_exposure, + .get = po1030_get_exposure + }, { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_RED_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_red_balance, + .get = po1030_get_red_balance + }, { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_BLUE_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_blue_balance, + .get = po1030_get_blue_balance + } + }, + .nmodes = 1, + .modes = { + { + M5602_DEFAULT_FRAME_WIDTH, + M5602_DEFAULT_FRAME_HEIGHT, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT, + .bytesperline = M5602_DEFAULT_FRAME_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } + } +}; + +static const unsigned char preinit_po1030[][3] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + + {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, + {BRIDGE, M5602_XB_SIG_INI, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x87}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + + {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00} +}; + +static const unsigned char init_po1030[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + /*sequence 1*/ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, + + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + /*end of sequence 1*/ + + /*sequence 2 (same as stop sequence)*/ + {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + /*end of sequence 2*/ + + /*sequence 5*/ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, + {BRIDGE, M5602_XB_SIG_INI, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x87}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + /*end of sequence 5*/ + + /*sequence 2 stop */ + {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + /*end of sequence 2 stop */ + +/* --------------------------------- + * end of init - begin of start + * --------------------------------- */ + + /*sequence 3*/ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + /*end of sequence 3*/ + /*sequence 4*/ + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + + {SENSOR, PO1030_REG_AUTOCTRL2, 0x04}, + + /* Set the width to 751 */ + {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02}, + {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef}, + + /* Set the height to 540 */ + {SENSOR, PO1030_REG_FRAMEHEIGHT_H, 0x02}, + {SENSOR, PO1030_REG_FRAMEHEIGHT_L, 0x1c}, + + /* Set the x window to 1 */ + {SENSOR, PO1030_REG_WINDOWX_H, 0x00}, + {SENSOR, PO1030_REG_WINDOWX_L, 0x01}, + + /* Set the y window to 1 */ + {SENSOR, PO1030_REG_WINDOWY_H, 0x00}, + {SENSOR, PO1030_REG_WINDOWX_L, 0x01}, + + {SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02}, + {SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87}, + {SENSOR, PO1030_REG_WINDOWHEIGHT_H, 0x01}, + {SENSOR, PO1030_REG_WINDOWHEIGHT_L, 0xe3}, + + {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04}, + {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04}, + {SENSOR, PO1030_REG_AUTOCTRL1, 0x08}, + {SENSOR, PO1030_REG_CONTROL2, 0x03}, + {SENSOR, 0x21, 0x90}, + {SENSOR, PO1030_REG_YTARGET, 0x60}, + {SENSOR, 0x59, 0x13}, + {SENSOR, PO1030_REG_OUTFORMCTRL1, 0x40}, + {SENSOR, 0x5f, 0x00}, + {SENSOR, 0x60, 0x80}, + {SENSOR, 0x78, 0x14}, + {SENSOR, 0x6f, 0x01}, + {SENSOR, PO1030_REG_CONTROL1, 0x18}, + {SENSOR, PO1030_REG_GLOBALGAINMAX, 0x14}, + {SENSOR, 0x63, 0x38}, + {SENSOR, 0x64, 0x38}, + {SENSOR, PO1030_REG_CONTROL1, 0x58}, + {SENSOR, PO1030_REG_RED_GAIN, 0x30}, + {SENSOR, PO1030_REG_GREEN_1_GAIN, 0x30}, + {SENSOR, PO1030_REG_BLUE_GAIN, 0x30}, + {SENSOR, PO1030_REG_GREEN_2_GAIN, 0x30}, + {SENSOR, PO1030_REG_GC0, 0x10}, + {SENSOR, PO1030_REG_GC1, 0x20}, + {SENSOR, PO1030_REG_GC2, 0x40}, + {SENSOR, PO1030_REG_GC3, 0x60}, + {SENSOR, PO1030_REG_GC4, 0x80}, + {SENSOR, PO1030_REG_GC5, 0xa0}, + {SENSOR, PO1030_REG_GC6, 0xc0}, + {SENSOR, PO1030_REG_GC7, 0xff}, + /*end of sequence 4*/ + /*sequence 5*/ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, + {BRIDGE, M5602_XB_SIG_INI, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x7e}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + /*end of sequence 5*/ + + /*sequence 6*/ + /* Changing 40 in f0 the image becomes green in bayer mode and red in + * rgb mode */ + {SENSOR, PO1030_REG_RED_GAIN, PO1030_RED_GAIN_DEFAULT}, + /* in changing 40 in f0 the image becomes green in bayer mode and red in + * rgb mode */ + {SENSOR, PO1030_REG_BLUE_GAIN, PO1030_BLUE_GAIN_DEFAULT}, + + /* with a very low lighted environment increase the exposure but + * decrease the FPS (Frame Per Second) */ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + + /* Controls high exposure more than SENSOR_LOW_EXPOSURE, use only in + * low lighted environment (f0 is more than ff ?)*/ + {SENSOR, PO1030_REG_INTEGLINES_H, ((PO1030_EXPOSURE_DEFAULT >> 2) + & 0xff)}, + + /* Controls middle exposure, use only in high lighted environment */ + {SENSOR, PO1030_REG_INTEGLINES_M, PO1030_EXPOSURE_DEFAULT & 0xff}, + + /* Controls clarity (not sure) */ + {SENSOR, PO1030_REG_INTEGLINES_L, 0x00}, + /* Controls gain (the image is more lighted) */ + {SENSOR, PO1030_REG_GLOBALGAIN, PO1030_GLOBAL_GAIN_DEFAULT}, + + /* Sets the width */ + {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02}, + {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef} + /*end of sequence 6*/ +}; + +#endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c new file mode 100644 index 000000000..682025653 --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -0,0 +1,463 @@ +/* + * Driver for the s5k4aa sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include "m5602_s5k4aa.h" + +int s5k4aa_probe(struct sd *sd) +{ + u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; + int i, err = 0; + + if (force_sensor) { + if (force_sensor == S5K4AA_SENSOR) { + info("Forcing a %s sensor", s5k4aa.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + info("Probing for a s5k4aa sensor"); + + /* Preinit the sensor */ + for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) { + u8 data[2] = {0x00, 0x00}; + + switch (preinit_s5k4aa[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + preinit_s5k4aa[i][1], + preinit_s5k4aa[i][2]); + break; + + case SENSOR: + data[0] = preinit_s5k4aa[i][2]; + err = s5k4aa_write_sensor(sd, + preinit_s5k4aa[i][1], + data, 1); + break; + + case SENSOR_LONG: + data[0] = preinit_s5k4aa[i][2]; + data[1] = preinit_s5k4aa[i][3]; + err = s5k4aa_write_sensor(sd, + preinit_s5k4aa[i][1], + data, 2); + break; + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + + /* Test some registers, but we don't know their exact meaning yet */ + if (s5k4aa_read_sensor(sd, 0x00, prod_id, sizeof(prod_id))) + return -ENODEV; + + if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) + return -ENODEV; + else + info("Detected a s5k4aa sensor"); +sensor_found: + sd->gspca_dev.cam.cam_mode = s5k4aa.modes; + sd->gspca_dev.cam.nmodes = s5k4aa.nmodes; + sd->desc->ctrls = s5k4aa.ctrls; + sd->desc->nctrls = s5k4aa.nctrls; + + return 0; +} + +int s5k4aa_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, + sd->sensor->i2c_slave_id); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); + if (err < 0) + goto out; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + if (err < 0) + goto out; + + for (i = 0; (i < len) & !err; i++) { + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); + + PDEBUG(DBG_TRACE, "Reading sensor register " + "0x%x containing 0x%x ", address, *i2c_data); + } +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + u8 *p; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* No sensor with a data width larger than 16 bits has yet been seen */ + if (len > 2 || !len) + return -EINVAL; + + memcpy(buf, sensor_urb_skeleton, + sizeof(sensor_urb_skeleton)); + + buf[11] = sd->sensor->i2c_slave_id; + buf[15] = address; + + /* Special case larger sensor writes */ + p = buf + 16; + + /* Copy a four byte write sequence for each byte to be written to */ + for (i = 0; i < len; i++) { + memcpy(p, sensor_urb_skeleton + 16, 4); + p[3] = i2c_data[i]; + p += 4; + PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x", + address, i2c_data[i]); + } + + /* Copy the tailer */ + memcpy(p, sensor_urb_skeleton + 20, 4); + + /* Set the total length */ + p[3] = 0x10 + len; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 20 + len * 4, M5602_URB_MSG_TIMEOUT); + + return (err < 0) ? err : 0; +} + +int s5k4aa_init(struct sd *sd) +{ + int i, err = 0; + + for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) { + u8 data[2] = {0x00, 0x00}; + + switch (init_s5k4aa[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + init_s5k4aa[i][1], + init_s5k4aa[i][2]); + break; + + case SENSOR: + data[0] = init_s5k4aa[i][2]; + err = s5k4aa_write_sensor(sd, + init_s5k4aa[i][1], data, 1); + break; + + case SENSOR_LONG: + data[0] = init_s5k4aa[i][2]; + data[1] = init_s5k4aa[i][3]; + err = s5k4aa_write_sensor(sd, + init_s5k4aa[i][1], data, 2); + break; + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + + if (dump_sensor) + s5k4aa_dump_registers(sd); + + if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) { + u8 data = 0x02; + info("vertical flip quirk active"); + s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + s5k4aa_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); + data |= S5K4AA_RM_V_FLIP; + data &= ~S5K4AA_RM_H_FLIP; + s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + + /* Decrement COLSTART to preserve color order (BGGR) */ + s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + data--; + s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + + /* Increment ROWSTART to preserve color order (BGGR) */ + s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + data++; + s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + } + + return (err < 0) ? err : 0; +} + +int s5k4aa_power_down(struct sd *sd) +{ + return 0; +} + +int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + + err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); + if (err < 0) + goto out; + + *val = data << 8; + err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); + *val |= data; + PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val); +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + PDEBUG(DBG_V4L2_CID, "Set exposure to %d", val); + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + data = (val >> 8) & 0xff; + err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); + if (err < 0) + goto out; + data = val & 0xff; + err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + + err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + *val = (data & S5K4AA_RM_V_FLIP) >> 7; + PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val); + +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val); + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + goto out; + data = ((data & ~S5K4AA_RM_V_FLIP) + | ((val & 0x01) << 7)); + err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + goto out; + + if (val) { + err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + if (err < 0) + goto out; + + data++; + err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + } else { + err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + if (err < 0) + goto out; + + data--; + err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + } +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + + err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + *val = (data & S5K4AA_RM_H_FLIP) >> 6; + PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val); +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", + val); + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + goto out; + + data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6)); + err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + goto out; + + if (val) { + err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + if (err < 0) + goto out; + data++; + err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + if (err < 0) + goto out; + } else { + err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + if (err < 0) + goto out; + data--; + err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + } +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + + err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1); + *val = data; + PDEBUG(DBG_V4L2_CID, "Read gain %d", *val); + +out: + return (err < 0) ? err : 0; +} + +int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + PDEBUG(DBG_V4L2_CID, "Set gain to %d", val); + err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + goto out; + + data = val & 0xff; + err = s5k4aa_write_sensor(sd, S5K4AA_GAIN_2, &data, 1); + +out: + return (err < 0) ? err : 0; +} + +void s5k4aa_dump_registers(struct sd *sd) +{ + int address; + u8 page, old_page; + s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); + for (page = 0; page < 16; page++) { + s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); + info("Dumping the s5k4aa register state for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 value = 0; + s5k4aa_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + } + info("s5k4aa register state dump complete"); + + for (page = 0; page < 16; page++) { + s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); + info("Probing for which registers that are " + "read/write for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 old_value, ctrl_value, test_value = 0xff; + + s5k4aa_read_sensor(sd, address, &old_value, 1); + s5k4aa_write_sensor(sd, address, &test_value, 1); + s5k4aa_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + s5k4aa_write_sensor(sd, address, &old_value, 1); + } + } + info("Read/write register probing complete"); + s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); +} diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h new file mode 100644 index 000000000..48abc6c8b --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h @@ -0,0 +1,372 @@ +/* + * Driver for the s5k4aa sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef M5602_S5K4AA_H_ +#define M5602_S5K4AA_H_ + +#include <linux/dmi.h> + +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define S5K4AA_PAGE_MAP 0xec + +#define S5K4AA_PAGE_MAP_0 0x00 +#define S5K4AA_PAGE_MAP_1 0x01 +#define S5K4AA_PAGE_MAP_2 0x02 + +/* Sensor register definitions for page 0x02 */ +#define S5K4AA_READ_MODE 0x03 +#define S5K4AA_ROWSTART_HI 0x04 +#define S5K4AA_ROWSTART_LO 0x05 +#define S5K4AA_COLSTART_HI 0x06 +#define S5K4AA_COLSTART_LO 0x07 +#define S5K4AA_WINDOW_HEIGHT_HI 0x08 +#define S5K4AA_WINDOW_HEIGHT_LO 0x09 +#define S5K4AA_WINDOW_WIDTH_HI 0x0a +#define S5K4AA_WINDOW_WIDTH_LO 0x0b +#define S5K4AA_GLOBAL_GAIN__ 0x0f /* Only a guess ATM !!! */ +#define S5K4AA_H_BLANK_HI__ 0x1d /* Only a guess ATM !!! sync lost + if too low, reduces frame rate + if too high */ +#define S5K4AA_H_BLANK_LO__ 0x1e /* Only a guess ATM !!! */ +#define S5K4AA_EXPOSURE_HI 0x17 +#define S5K4AA_EXPOSURE_LO 0x18 +#define S5K4AA_GAIN_1 0x1f /* (digital?) gain : 5 bits */ +#define S5K4AA_GAIN_2 0x20 /* (analogue?) gain : 7 bits */ + +#define S5K4AA_RM_ROW_SKIP_4X 0x08 +#define S5K4AA_RM_ROW_SKIP_2X 0x04 +#define S5K4AA_RM_COL_SKIP_4X 0x02 +#define S5K4AA_RM_COL_SKIP_2X 0x01 +#define S5K4AA_RM_H_FLIP 0x40 +#define S5K4AA_RM_V_FLIP 0x80 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; +extern unsigned int m5602_debug; + +int s5k4aa_probe(struct sd *sd); +int s5k4aa_init(struct sd *sd); +int s5k4aa_power_down(struct sd *sd); + +void s5k4aa_dump_registers(struct sd *sd); + +int s5k4aa_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); +int s5k4aa_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val); + +static struct m5602_sensor s5k4aa = { + .name = "S5K4AA", + .probe = s5k4aa_probe, + .init = s5k4aa_init, + .power_down = s5k4aa_power_down, + .read_sensor = s5k4aa_read_sensor, + .write_sensor = s5k4aa_write_sensor, + .i2c_slave_id = 0x5a, + .nctrls = 4, + .ctrls = { + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k4aa_set_vflip, + .get = s5k4aa_get_vflip + + }, { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k4aa_set_hflip, + .get = s5k4aa_get_hflip + + }, { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0xa0, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k4aa_set_gain, + .get = s5k4aa_get_gain + }, { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 13, + .maximum = 0xfff, + .step = 1, + .default_value = 0x100, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k4aa_set_exposure, + .get = s5k4aa_get_exposure + } + }, + + .nmodes = 1, + .modes = { + { + M5602_DEFAULT_FRAME_WIDTH, + M5602_DEFAULT_FRAME_HEIGHT, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT, + .bytesperline = M5602_DEFAULT_FRAME_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } + } +}; + +static const unsigned char preinit_s5k4aa[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00} +}; + +static const unsigned char init_s5k4aa[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00}, + {SENSOR, 0x36, 0x01, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}, + {SENSOR, 0x7b, 0xff, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, 0x0c, 0x05, 0x00}, + {SENSOR, 0x02, 0x0e, 0x00}, + {SENSOR, S5K4AA_GAIN_1, 0x0f, 0x00}, + {SENSOR, S5K4AA_GAIN_2, 0x00, 0x00}, + {SENSOR, S5K4AA_GLOBAL_GAIN__, 0x01, 0x00}, + {SENSOR, 0x11, 0x00, 0x00}, + {SENSOR, 0x12, 0x00, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00}, + {SENSOR, 0x37, 0x00, 0x00}, + {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00}, + {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_COLSTART_LO, 0x0b, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc4, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x08, 0x00}, + {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, + {SENSOR, S5K4AA_H_BLANK_LO__, 0x48, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_LO, 0x43, 0x00}, + {SENSOR, 0x11, 0x04, 0x00}, + {SENSOR, 0x12, 0xc3, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ + + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X + | S5K4AA_RM_COL_SKIP_2X, 0x00}, + /* 0x37 : Fix image stability when light is too bright and improves + * image quality in 640x480, but worsens it in 1280x1024 */ + {SENSOR, 0x37, 0x01, 0x00}, + /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */ + {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00}, + {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00}, + /* window_height_hi, window_height_lo : 960 = 0x03c0 */ + {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00}, + /* window_width_hi, window_width_lo : 1280 = 0x0500 */ + {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, + {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, + {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */ + {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, + {SENSOR, 0x11, 0x04, 0x00}, + {SENSOR, 0x12, 0xc3, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, 0x02, 0x0e, 0x00}, + {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00}, + {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00}, + {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00} +}; + +static +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + const +#endif + struct dmi_system_id s5k4aa_vflip_dmi_table[] = { + { + .ident = "Fujitsu-Siemens Amilo Xa 2528", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") + } + }, + { + .ident = "Fujitsu-Siemens Amilo Xi 2550", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") + } + }, + { + .ident = "MSI GX700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), + DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") + } + }, + { } +}; + +#endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c new file mode 100644 index 000000000..b4b33c2d0 --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c @@ -0,0 +1,423 @@ +/* + * Driver for the s5k83a sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include "m5602_s5k83a.h" + +int s5k83a_probe(struct sd *sd) +{ + u8 prod_id = 0, ver_id = 0; + int i, err = 0; + + if (force_sensor) { + if (force_sensor == S5K83A_SENSOR) { + info("Forcing a %s sensor", s5k83a.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + info("Probing for a s5k83a sensor"); + + /* Preinit the sensor */ + for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) { + u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]}; + if (preinit_s5k83a[i][0] == SENSOR) + err = s5k83a_write_sensor(sd, preinit_s5k83a[i][1], + data, 2); + else + err = m5602_write_bridge(sd, preinit_s5k83a[i][1], + data[0]); + } + + /* We don't know what register (if any) that contain the product id + * Just pick the first addresses that seem to produce the same results + * on multiple machines */ + if (s5k83a_read_sensor(sd, 0x00, &prod_id, 1)) + return -ENODEV; + + if (s5k83a_read_sensor(sd, 0x01, &ver_id, 1)) + return -ENODEV; + + if ((prod_id == 0xff) || (ver_id == 0xff)) + return -ENODEV; + else + info("Detected a s5k83a sensor"); + +sensor_found: + sd->gspca_dev.cam.cam_mode = s5k83a.modes; + sd->gspca_dev.cam.nmodes = s5k83a.nmodes; + sd->desc->ctrls = s5k83a.ctrls; + sd->desc->nctrls = s5k83a.nctrls; + return 0; +} + +int s5k83a_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, + sd->sensor->i2c_slave_id); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); + if (err < 0) + goto out; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + + if (err < 0) + goto out; + for (i = 0; i < len && !len; i++) { + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); + + PDEBUG(DBG_TRACE, "Reading sensor register " + "0x%x containing 0x%x ", address, *i2c_data); + } + +out: + return (err < 0) ? err : 0; +} + +int s5k83a_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + u8 *p; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* No sensor with a data width larger than 16 bits has yet been seen */ + if (len > 2 || !len) + return -EINVAL; + + memcpy(buf, sensor_urb_skeleton, + sizeof(sensor_urb_skeleton)); + + buf[11] = sd->sensor->i2c_slave_id; + buf[15] = address; + + /* Special case larger sensor writes */ + p = buf + 16; + + /* Copy a four byte write sequence for each byte to be written to */ + for (i = 0; i < len; i++) { + memcpy(p, sensor_urb_skeleton + 16, 4); + p[3] = i2c_data[i]; + p += 4; + PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x", + address, i2c_data[i]); + } + + /* Copy the tailer */ + memcpy(p, sensor_urb_skeleton + 20, 4); + + /* Set the total length */ + p[3] = 0x10 + len; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 20 + len * 4, M5602_URB_MSG_TIMEOUT); + + return (err < 0) ? err : 0; +} + +int s5k83a_init(struct sd *sd) +{ + int i, err = 0; + + for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) { + u8 data[2] = {0x00, 0x00}; + + switch (init_s5k83a[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + init_s5k83a[i][1], + init_s5k83a[i][2]); + break; + + case SENSOR: + data[0] = init_s5k83a[i][2]; + err = s5k83a_write_sensor(sd, + init_s5k83a[i][1], data, 1); + break; + + case SENSOR_LONG: + data[0] = init_s5k83a[i][2]; + data[1] = init_s5k83a[i][3]; + err = s5k83a_write_sensor(sd, + init_s5k83a[i][1], data, 2); + break; + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + + if (dump_sensor) + s5k83a_dump_registers(sd); + + return (err < 0) ? err : 0; +} + +int s5k83a_power_down(struct sd *sd) +{ + return 0; +} + +void s5k83a_dump_registers(struct sd *sd) +{ + int address; + u8 page, old_page; + s5k83a_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); + + for (page = 0; page < 16; page++) { + s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); + info("Dumping the s5k83a register state for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 val = 0; + s5k83a_read_sensor(sd, address, &val, 1); + info("register 0x%x contains 0x%x", + address, val); + } + } + info("s5k83a register state dump complete"); + + for (page = 0; page < 16; page++) { + s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); + info("Probing for which registers that are read/write " + "for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 old_val, ctrl_val, test_val = 0xff; + + s5k83a_read_sensor(sd, address, &old_val, 1); + s5k83a_write_sensor(sd, address, &test_val, 1); + s5k83a_read_sensor(sd, address, &ctrl_val, 1); + + if (ctrl_val == test_val) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original val */ + s5k83a_write_sensor(sd, address, &old_val, 1); + } + } + info("Read/write register probing complete"); + s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); +} + +int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + + err = s5k83a_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2); + data[1] = data[1] << 1; + *val = data[1]; + + return (err < 0) ? err : 0; +} + +int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0x00; + data[1] = 0x20; + err = s5k83a_write_sensor(sd, 0x14, data, 2); + if (err < 0) + return err; + + data[0] = 0x01; + data[1] = 0x00; + err = s5k83a_write_sensor(sd, 0x0d, data, 2); + if (err < 0) + return err; + + /* FIXME: This is not sane, we need to figure out the composition + of these registers */ + data[0] = val >> 3; /* brightness, high 5 bits */ + data[1] = val >> 1; /* brightness, high 7 bits */ + err = s5k83a_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2); + + return (err < 0) ? err : 0; +} + +int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 data; + struct sd *sd = (struct sd *) gspca_dev; + + err = s5k83a_read_sensor(sd, S5K83A_WHITENESS, &data, 1); + + *val = data; + return (err < 0) ? err : 0; +} + +int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = val; + err = s5k83a_write_sensor(sd, S5K83A_WHITENESS, data, 1); + + return (err < 0) ? err : 0; +} + +int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + + err = s5k83a_read_sensor(sd, S5K83A_GAIN, data, 2); + + data[1] = data[1] & 0x3f; + if (data[1] > S5K83A_MAXIMUM_GAIN) + data[1] = S5K83A_MAXIMUM_GAIN; + + *val = data[1]; + + return (err < 0) ? err : 0; +} + +int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0; + data[1] = val; + err = s5k83a_write_sensor(sd, S5K83A_GAIN, data, 2); + + return (err < 0) ? err : 0; +} + +int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0x05; + err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + if (err < 0) + return err; + + err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + *val = (data[0] | 0x40) ? 1 : 0; + + return (err < 0) ? err : 0; +} + +int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0x05; + err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + if (err < 0) + return err; + + err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + if (err < 0) + return err; + + /* set or zero six bit, seven is hflip */ + data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK + : (data[0] & 0x80) | S5K83A_FLIP_MASK; + err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1); + if (err < 0) + return err; + + data[0] = (val) ? 0x0b : 0x0a; + err = s5k83a_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); + + return (err < 0) ? err : 0; +} + +int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0x05; + err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + if (err < 0) + return err; + + err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + *val = (data[0] | 0x80) ? 1 : 0; + + return (err < 0) ? err : 0; +} + +int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0x05; + err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + if (err < 0) + return err; + + err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + if (err < 0) + return err; + + /* set or zero seven bit, six is vflip */ + data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK + : (data[0] & 0x40) | S5K83A_FLIP_MASK; + err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1); + if (err < 0) + return err; + + data[0] = (val) ? 0x0a : 0x0b; + err = s5k83a_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); + + return (err < 0) ? err : 0; +} diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h new file mode 100644 index 000000000..833708eb5 --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h @@ -0,0 +1,484 @@ +/* + * Driver for the s5k83a sensor + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef M5602_S5K83A_H_ +#define M5602_S5K83A_H_ + +#include "m5602_sensor.h" + +#define S5K83A_FLIP 0x01 +#define S5K83A_HFLIP_TUNE 0x03 +#define S5K83A_VFLIP_TUNE 0x05 +#define S5K83A_WHITENESS 0x0a +#define S5K83A_GAIN 0x18 +#define S5K83A_BRIGHTNESS 0x1b +#define S5K83A_PAGE_MAP 0xec + +#define S5K83A_DEFAULT_BRIGHTNESS 0x71 +#define S5K83A_DEFAULT_WHITENESS 0x7e +#define S5K83A_DEFAULT_GAIN 0x00 +#define S5K83A_MAXIMUM_GAIN 0x3c +#define S5K83A_FLIP_MASK 0x10 + + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; +extern unsigned int m5602_debug; + + +int s5k83a_probe(struct sd *sd); +int s5k83a_init(struct sd *sd); +int s5k83a_power_down(struct sd *sd); + +void s5k83a_dump_registers(struct sd *sd); + +int s5k83a_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); +int s5k83a_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); +int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); +int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val); +int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val); +int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); +int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val); + + +static struct m5602_sensor s5k83a = { + .name = "S5K83A", + .probe = s5k83a_probe, + .init = s5k83a_init, + .power_down = s5k83a_power_down, + .read_sensor = s5k83a_read_sensor, + .write_sensor = s5k83a_write_sensor, + .i2c_slave_id = 0x5a, + .nctrls = 5, + .ctrls = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = S5K83A_DEFAULT_BRIGHTNESS, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k83a_set_brightness, + .get = s5k83a_get_brightness + + }, { + { + .id = V4L2_CID_WHITENESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "whiteness", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = S5K83A_DEFAULT_WHITENESS, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k83a_set_whiteness, + .get = s5k83a_get_whiteness, + }, { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = S5K83A_MAXIMUM_GAIN, + .step = 0x01, + .default_value = S5K83A_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k83a_set_gain, + .get = s5k83a_get_gain + }, { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k83a_set_hflip, + .get = s5k83a_get_hflip + }, { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k83a_set_vflip, + .get = s5k83a_get_vflip + } + }, + .nmodes = 1, + .modes = { + { + M5602_DEFAULT_FRAME_WIDTH, + M5602_DEFAULT_FRAME_HEIGHT, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT, + .bytesperline = M5602_DEFAULT_FRAME_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } + } +}; + +static const unsigned char preinit_s5k83a[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00} +}; + +/* This could probably be considerably shortened. + I don't have the hardware to experiment with it, patches welcome +*/ +static const unsigned char init_s5k83a[][4] = +{ + {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, + {SENSOR, 0xaf, 0x01, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}, + {SENSOR, 0x7b, 0xff, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x01, 0x50, 0x00}, + {SENSOR, 0x12, 0x20, 0x00}, + {SENSOR, 0x17, 0x40, 0x00}, + {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, + {SENSOR, 0x1c, 0x00, 0x00}, + {SENSOR, 0x02, 0x70, 0x00}, + {SENSOR, 0x03, 0x0b, 0x00}, + {SENSOR, 0x04, 0xf0, 0x00}, + {SENSOR, 0x05, 0x0b, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x06, 0x71, 0x00}, + {SENSOR, 0x07, 0xe8, 0x00}, + {SENSOR, 0x08, 0x02, 0x00}, + {SENSOR, 0x09, 0x88, 0x00}, + {SENSOR, 0x14, 0x00, 0x00}, + {SENSOR, 0x15, 0x20, 0x00}, + {SENSOR, 0x19, 0x00, 0x00}, + {SENSOR, 0x1a, 0x98, 0x00}, + {SENSOR, 0x0f, 0x02, 0x00}, + {SENSOR, 0x10, 0xe5, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR_LONG, 0x14, 0x00, 0x20}, + {SENSOR_LONG, 0x0d, 0x00, 0x7d}, + {SENSOR_LONG, 0x1b, 0x0d, 0x05}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00}, + + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, + {SENSOR, 0xaf, 0x01, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + /* ff ( init value )is very dark) || 71 and f0 better */ + {SENSOR, 0x7b, 0xff, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x01, 0x50, 0x00}, + {SENSOR, 0x12, 0x20, 0x00}, + {SENSOR, 0x17, 0x40, 0x00}, + {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, + {SENSOR, 0x1c, 0x00, 0x00}, + {SENSOR, 0x02, 0x70, 0x00}, + /* some values like 0x10 give a blue-purple image */ + {SENSOR, 0x03, 0x0b, 0x00}, + {SENSOR, 0x04, 0xf0, 0x00}, + {SENSOR, 0x05, 0x0b, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + /* under 80 don't work, highter depend on value */ + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, + + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x06, 0x71, 0x00}, + {SENSOR, 0x07, 0xe8, 0x00}, + {SENSOR, 0x08, 0x02, 0x00}, + {SENSOR, 0x09, 0x88, 0x00}, + {SENSOR, 0x14, 0x00, 0x00}, + {SENSOR, 0x15, 0x20, 0x00}, + {SENSOR, 0x19, 0x00, 0x00}, + {SENSOR, 0x1a, 0x98, 0x00}, + {SENSOR, 0x0f, 0x02, 0x00}, + {SENSOR, 0x10, 0xe5, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR_LONG, 0x14, 0x00, 0x20}, + {SENSOR_LONG, 0x0d, 0x00, 0x7d}, + {SENSOR_LONG, 0x1b, 0x0d, 0x05}, + + /* The following sequence is useless after a clean boot + but is necessary after resume from suspend */ + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, + {SENSOR, 0xaf, 0x01, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}, + {SENSOR, 0x7b, 0xff, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x01, 0x50, 0x00}, + {SENSOR, 0x12, 0x20, 0x00}, + {SENSOR, 0x17, 0x40, 0x00}, + {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, + {SENSOR, 0x1c, 0x00, 0x00}, + {SENSOR, 0x02, 0x70, 0x00}, + {SENSOR, 0x03, 0x0b, 0x00}, + {SENSOR, 0x04, 0xf0, 0x00}, + {SENSOR, 0x05, 0x0b, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x06, 0x71, 0x00}, + {SENSOR, 0x07, 0xe8, 0x00}, + {SENSOR, 0x08, 0x02, 0x00}, + {SENSOR, 0x09, 0x88, 0x00}, + {SENSOR, 0x14, 0x00, 0x00}, + {SENSOR, 0x15, 0x20, 0x00}, + {SENSOR, 0x19, 0x00, 0x00}, + {SENSOR, 0x1a, 0x98, 0x00}, + {SENSOR, 0x0f, 0x02, 0x00}, + + {SENSOR, 0x10, 0xe5, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR_LONG, 0x14, 0x00, 0x20}, + {SENSOR_LONG, 0x0d, 0x00, 0x7d}, + {SENSOR_LONG, 0x1b, 0x0d, 0x05}, + + /* normal colors + (this is value after boot, but after tries can be different) */ + {SENSOR, 0x00, 0x06, 0x00}, + + /* set default brightness */ + {SENSOR_LONG, 0x14, 0x00, 0x20}, + {SENSOR_LONG, 0x0d, 0x01, 0x00}, + {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3, + S5K83A_DEFAULT_BRIGHTNESS >> 1}, + + /* set default whiteness */ + {SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00}, + + /* set default gain */ + {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN}, + + /* set default flip */ + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00}, + {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00}, + {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00} + +}; + +#endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_sensor.h b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h new file mode 100644 index 000000000..930fcaab4 --- /dev/null +++ b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h @@ -0,0 +1,76 @@ +/* + * USB Driver for ALi m5602 based webcams + * + * Copyright (C) 2008 Erik Andren + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef M5602_SENSOR_H_ +#define M5602_SENSOR_H_ + +#include "m5602_bridge.h" + +#define M5602_DEFAULT_FRAME_WIDTH 640 +#define M5602_DEFAULT_FRAME_HEIGHT 480 + +#define M5602_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10) + +/* Enumerates all supported sensors */ +enum sensors { + OV9650_SENSOR = 1, + S5K83A_SENSOR = 2, + S5K4AA_SENSOR = 3, + MT9M111_SENSOR = 4, + PO1030_SENSOR = 5 +}; + +/* Enumerates all possible instruction types */ +enum instruction { + BRIDGE, + SENSOR, + SENSOR_LONG +}; + +struct m5602_sensor { + /* Defines the name of a sensor */ + char name[32]; + + /* What i2c address the sensor is connected to */ + u8 i2c_slave_id; + + /* Probes if the sensor is connected */ + int (*probe)(struct sd *sd); + + /* Performs a initialization sequence */ + int (*init)(struct sd *sd); + + /* Performs a power down sequence */ + int (*power_down)(struct sd *sd); + + /* Reads a sensor register */ + int (*read_sensor)(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + + /* Writes to a sensor register */ + int (*write_sensor)(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + + int nctrls; + struct ctrl ctrls[M5602_MAX_CTRLS]; + + char nmodes; + struct v4l2_pix_format modes[]; +}; + +#endif diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c index 4d5db47ba..277ca34a8 100644 --- a/linux/drivers/media/video/gspca/mars.c +++ b/linux/drivers/media/video/gspca/mars.c @@ -134,7 +134,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { int err_code; __u8 *data; @@ -143,9 +143,10 @@ static void sd_start(struct gspca_dev *gspca_dev) int intpipe; PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface); - if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8) < 0) { + err_code = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8); + if (err_code < 0) { PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error"); - return; + return err_code; } data = gspca_dev->usb_buf; @@ -154,7 +155,7 @@ static void sd_start(struct gspca_dev *gspca_dev) err_code = reg_w(gspca_dev, data[0], 2); if (err_code < 0) - return; + return err_code; /* Initialize the MR97113 chip register @@ -180,14 +181,14 @@ static void sd_start(struct gspca_dev *gspca_dev) err_code = reg_w(gspca_dev, data[0], 11); if (err_code < 0) - return; + return err_code; data[0] = 0x23; /* address */ data[1] = 0x09; /* reg 35, append frame header */ err_code = reg_w(gspca_dev, data[0], 2); if (err_code < 0) - return; + return err_code; data[0] = 0x3c; /* address */ /* if (gspca_dev->width == 1280) */ @@ -198,7 +199,7 @@ static void sd_start(struct gspca_dev *gspca_dev) * (unit: 4KB) 200KB */ err_code = reg_w(gspca_dev, data[0], 2); if (err_code < 0) - return; + return err_code; if (0) { /* fixed dark-gain */ data[1] = 0; /* reg 94, Y Gain (1.75) */ @@ -240,13 +241,13 @@ static void sd_start(struct gspca_dev *gspca_dev) err_code = reg_w(gspca_dev, data[0], 6); if (err_code < 0) - return; + return err_code; data[0] = 0x67; data[1] = 0x13; /* reg 103, first pixel B, disable sharpness */ err_code = reg_w(gspca_dev, data[0], 2); if (err_code < 0) - return; + return err_code; /* * initialize the value of MI sensor... @@ -326,6 +327,7 @@ static void sd_start(struct gspca_dev *gspca_dev) data[0] = 0x00; data[1] = 0x4d; /* ISOC transfering enable... */ reg_w(gspca_dev, data[0], 2); + return err_code; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c index bb2842114..895bcf082 100644 --- a/linux/drivers/media/video/gspca/ov519.c +++ b/linux/drivers/media/video/gspca/ov519.c @@ -1879,7 +1879,7 @@ static int set_ov_sensor_window(struct sd *sd) } /* -- start the camera -- */ -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int ret; @@ -1896,9 +1896,10 @@ static void sd_start(struct gspca_dev *gspca_dev) goto out; PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); ov51x_led_control(sd, 1); - return; + return 0; out: PDEBUG(D_ERR, "camera start error:%d", ret); + return ret; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index 34e923d00..0b0c573d0 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -281,7 +281,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } /* -- start the camera -- */ -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 mode; @@ -323,6 +323,7 @@ static void sd_start(struct gspca_dev *gspca_dev) sd->sof_read = 0; sd->autogain_ignore_frames = 0; atomic_set(&sd->avg_lum, -1); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 296ba82e6..a122634e0 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -689,7 +689,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -738,6 +738,7 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x78, 0x01); else reg_w(gspca_dev, 0x78, 0x05); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c index 53cb724bf..4bae911da 100644 --- a/linux/drivers/media/video/gspca/sonixb.c +++ b/linux/drivers/media/video/gspca/sonixb.c @@ -922,7 +922,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } /* -- start the camera -- */ -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam = &gspca_dev->cam; @@ -1006,6 +1006,7 @@ static void sd_start(struct gspca_dev *gspca_dev) sd->frames_to_drop = 0; sd->autogain_ignore_frames = 0; atomic_set(&sd->avg_lum, -1); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index a77164581..aa11df134 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -144,7 +144,7 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define VFLIP_DEF 0 +#define VFLIP_DEF 1 .default_value = VFLIP_DEF, }, .set = sd_setvflip, @@ -241,17 +241,6 @@ static const __u8 sn_ov7648[] = { }; static const __u8 sn_ov7660[] = { -#if 0 -/*jfm: from win trace */ -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x01, 0x01, 0x14, 0x28, 0x1e, 0x00, -/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -#else /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, /* reg8 reg9 rega regb regc regd rege regf */ @@ -260,7 +249,6 @@ static const __u8 sn_ov7660[] = { 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -#endif }; /* sequence specific to the sensors - !! index = SENSOR_xxx */ @@ -279,14 +267,12 @@ static const __u8 gamma_def[] = { 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff }; +/* color matrix and offsets */ static const __u8 reg84[] = { - 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f, - 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f, -#if 1 - 0xf7, 0x0f, 0x00, 0x00, 0x00 -#else - 0xf7, 0x0f, 0x0a, 0x00, 0x00 -#endif + 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, /* YR YG YB gains */ + 0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00, /* UR UG UB */ + 0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f, /* VR VG VB */ + 0x00, 0x00, 0x00 /* YUV offsets */ }; static const __u8 hv7131r_sensor_init[][8] = { {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10}, @@ -743,6 +729,7 @@ static void i2c_w8(struct gspca_dev *gspca_dev, 0x08, 0, /* value, index */ gspca_dev->usb_buf, 8, 500); + msleep(2); } /* read 5 bytes in gspca_dev->usb_buf */ @@ -1022,13 +1009,13 @@ static int sd_init(struct gspca_dev *gspca_dev) case BRIDGE_SN9C105: if (regF1 != 0x11) return -ENODEV; - reg_w(gspca_dev, 0x02, regGpio, 2); + reg_w(gspca_dev, 0x01, regGpio, 2); break; case BRIDGE_SN9C120: if (regF1 != 0x12) return -ENODEV; regGpio[1] = 0x70; - reg_w(gspca_dev, 0x02, regGpio, 2); + reg_w(gspca_dev, 0x01, regGpio, 2); break; default: /* case BRIDGE_SN9C110: */ @@ -1130,20 +1117,17 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev, static void setbrightcont(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - unsigned val; + int val; __u8 reg84_full[0x15]; - 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 + memcpy(reg84_full, reg84, sizeof reg84_full); + val = sd->contrast * 0x30 / CONTRAST_MAX + 0x10; /* 10..40 */ + reg84_full[0] = (val + 1) / 2; /* red */ + reg84_full[2] = val; /* green */ + reg84_full[4] = (val + 1) / 5; /* blue */ + val = (sd->brightness - BRIGHTNESS_DEF) * 0x10 / BRIGHTNESS_MAX; - else - val = 0; - reg84_full[0x12] = val; /* 00..1f */ + reg84_full[0x12] = val & 0x1f; /* 5:0 signed value */ reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full); } @@ -1231,7 +1215,7 @@ static void setvflip(struct sd *sd) } /* -- start the camera -- */ -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i; @@ -1242,7 +1226,7 @@ static void sd_start(struct gspca_dev *gspca_dev) static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ static const __u8 CE_ov76xx[] = - { 0x32, 0xdd, 0x32, 0xdd }; /* OV7630/48 */ + { 0x32, 0xdd, 0x32, 0xdd }; sn9c1xx = sn_tb[(int) sd->sensor]; configure_gpio(gspca_dev, sn9c1xx); @@ -1284,20 +1268,15 @@ static void sd_start(struct gspca_dev *gspca_dev) 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_w1(gspca_dev, 0x9a, 0x0a); - reg_w1(gspca_dev, 0x99, 0x60); + switch (sd->sensor) { + case SENSOR_OV7660: + reg_w1(gspca_dev, 0x9a, 0x05); break; default: -#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) @@ -1349,14 +1328,8 @@ static void sd_start(struct gspca_dev *gspca_dev) /* reg1 = 0x44; */ /* reg1 = 0x46; (done) */ } else { -#if 0 -/*jfm: from win trace */ reg17 = 0xa2; /* 640 */ - reg1 = 0x40; -#else - reg17 = 0x22; /* 640 MCKSIZE */ - reg1 = 0x06; -#endif + reg1 = 0x44; } break; } @@ -1365,6 +1338,7 @@ static void sd_start(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_OV7630: case SENSOR_OV7648: + case SENSOR_OV7660: reg_w(gspca_dev, 0xce, CE_ov76xx, 4); break; default: @@ -1391,12 +1365,16 @@ static void sd_start(struct gspca_dev *gspca_dev) setbrightness(gspca_dev); setcontrast(gspca_dev); break; + case SENSOR_OV7630: + setvflip(sd); + /* fall thru */ default: /* OV76xx */ setbrightcont(gspca_dev); break; } setautogain(gspca_dev); reg_w1(gspca_dev, 0x01, reg1); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -1622,7 +1600,8 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->vflip = val; - setvflip(sd); + if (gspca_dev->streaming) + setvflip(sd); return 0; } @@ -1677,7 +1656,9 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */ {USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)}, -/* {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x??)}, */ +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)}, +#endif /* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c index c33bfe48c..a3f616709 100644 --- a/linux/drivers/media/video/gspca/spca500.c +++ b/linux/drivers/media/video/gspca/spca500.c @@ -677,7 +677,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int err; @@ -884,6 +884,7 @@ static void sd_start(struct gspca_dev *gspca_dev) write_vector(gspca_dev, Clicksmart510_defaults); break; } + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c index 49e512cac..979344907 100644 --- a/linux/drivers/media/video/gspca/spca501.c +++ b/linux/drivers/media/video/gspca/spca501.c @@ -1991,7 +1991,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; int mode; @@ -2023,6 +2023,7 @@ static void sd_start(struct gspca_dev *gspca_dev) setbrightness(gspca_dev); setcontrast(gspca_dev); setcolors(gspca_dev); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c index e33666df4..62bab3cc1 100644 --- a/linux/drivers/media/video/gspca/spca505.c +++ b/linux/drivers/media/video/gspca/spca505.c @@ -757,7 +757,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; int ret; @@ -802,6 +802,7 @@ static void sd_start(struct gspca_dev *gspca_dev) /* reg_write(dev, 0x5, 0x0, 0x0); */ /* reg_write(dev, 0x5, 0x0, 0x1); */ /* reg_write(dev, 0x5, 0x11, 0x2); */ + return ret; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c index 195dce96e..645ee9d44 100644 --- a/linux/drivers/media/video/gspca/spca506.c +++ b/linux/drivers/media/video/gspca/spca506.c @@ -422,7 +422,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; __u16 norme; @@ -549,6 +549,7 @@ static void sd_start(struct gspca_dev *gspca_dev) PDEBUG(D_STREAM, "webcam started"); spca506_GetNormeInput(gspca_dev, &norme, &channel); spca506_SetNormeInput(gspca_dev, norme, channel); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c index 5e3f66ae2..c9360cdb8 100644 --- a/linux/drivers/media/video/gspca/spca508.c +++ b/linux/drivers/media/video/gspca/spca508.c @@ -1566,7 +1566,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { int mode; @@ -1584,6 +1584,7 @@ static void sd_start(struct gspca_dev *gspca_dev) break; } reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index 0250ee96d..5b65dd66b 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -152,7 +152,7 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, /* request */ - USB_TYPE_VENDOR | USB_RECIP_DEVICE, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); if (ret < 0) @@ -225,7 +225,7 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01)); do { reg_r(gspca_dev, 0x8803, 1); - if (!gspca_dev->usb_buf) + if (!gspca_dev->usb_buf[0]) break; } while (--retry); if (retry == 0) @@ -713,7 +713,7 @@ static void setautogain(struct gspca_dev *gspca_dev) sd->ag_cnt = -1; } -static void sd_start_12a(struct gspca_dev *gspca_dev) +static int sd_start_12a(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */ @@ -739,8 +739,9 @@ static void sd_start_12a(struct gspca_dev *gspca_dev) setwhite(gspca_dev); setautogain(gspca_dev); setexposure(gspca_dev); + return 0; } -static void sd_start_72a(struct gspca_dev *gspca_dev) +static int sd_start_72a(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; int Clck; @@ -764,6 +765,7 @@ static void sd_start_72a(struct gspca_dev *gspca_dev) reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ reg_w_val(dev, 0x8112, 0x10 | 0x20); setautogain(gspca_dev); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -1078,7 +1080,7 @@ static struct ctrl sd_ctrls_12a[] = { { .id = V4L2_CID_DO_WHITE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", + .name = "White Balance", .minimum = WHITE_MIN, .maximum = WHITE_MAX, .step = 1, diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c index 2f2de429e..d9d64911f 100644 --- a/linux/drivers/media/video/gspca/stk014.c +++ b/linux/drivers/media/video/gspca/stk014.c @@ -324,7 +324,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } /* -- start the camera -- */ -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { int ret, value; @@ -374,9 +374,10 @@ static void sd_start(struct gspca_dev *gspca_dev) set_par(gspca_dev, 0x01000000); set_par(gspca_dev, 0x01000000); PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); - return; + return 0; out: PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret); + return ret; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c index e8e5c47ba..3a972ff1c 100644 --- a/linux/drivers/media/video/gspca/sunplus.c +++ b/linux/drivers/media/video/gspca/sunplus.c @@ -992,7 +992,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; @@ -1073,6 +1073,7 @@ static void sd_start(struct gspca_dev *gspca_dev) break; } sp5xx_initContBrigHueRegisters(gspca_dev); + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c index c7673661a..df3f1ff9d 100644 --- a/linux/drivers/media/video/gspca/t613.c +++ b/linux/drivers/media/video/gspca/t613.c @@ -28,8 +28,6 @@ #include "gspca.h" -#define MAX_GAMMA 0x10 /* 0 to 15 */ - #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0) MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>"); @@ -49,6 +47,10 @@ struct sd { unsigned char whitebalance; unsigned char mirror; unsigned char effect; + + __u8 sensor; +#define SENSOR_TAS5130A 0 +#define SENSOR_OTHER 1 }; /* V4L2 controls supported by the driver */ @@ -83,9 +85,9 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", .minimum = 0, - .maximum = 0x0f, + .maximum = 14, .step = 1, - .default_value = 0x09, + .default_value = 8, }, .set = sd_setbrightness, .get = sd_getbrightness, @@ -118,16 +120,17 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcolors, .get = sd_getcolors, }, -#define SD_GAMMA 3 +#define GAMMA_MAX 16 +#define GAMMA_DEF 10 { { .id = V4L2_CID_GAMMA, /* (gamma on win) */ .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma (Untested)", + .name = "Gamma", .minimum = 0, - .maximum = MAX_GAMMA, + .maximum = GAMMA_MAX - 1, .step = 1, - .default_value = 0x09, + .default_value = GAMMA_DEF, }, .set = sd_setgamma, .get = sd_getgamma, @@ -197,7 +200,7 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Sharpness", .minimum = 0, - .maximum = MAX_GAMMA, /* 0 to 16 */ + .maximum = 15, .step = 1, .default_value = 0x06, }, @@ -258,7 +261,6 @@ static struct v4l2_pix_format vga_mode_t16[] = { .priv = 0}, }; -#define T16_OFFSET_DATA 631 #define MAX_EFFECTS 7 /* easily done by soft, this table could be removed, * i keep it here just in case */ @@ -272,87 +274,87 @@ static const __u8 effects_table[MAX_EFFECTS][6] = { {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */ }; -static const __u8 gamma_table[MAX_GAMMA][34] = { - {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85, +static const __u8 gamma_table[GAMMA_MAX][34] = { + {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85, /* 0 */ 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9, 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb, 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75, - 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD, - 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4, - 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7, + {0x90, 0x00, 0x91, 0x33, 0x92, 0x5a, 0x93, 0x75, /* 1 */ + 0x94, 0x85, 0x95, 0x93, 0x96, 0xa1, 0x97, 0xad, + 0x98, 0xb7, 0x99, 0xc2, 0x9a, 0xcb, 0x9b, 0xd4, + 0x9c, 0xde, 0x9D, 0xe7, 0x9e, 0xf0, 0x9f, 0xf7, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B, - 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6, - 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0, - 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6, + {0x90, 0x00, 0x91, 0x2f, 0x92, 0x51, 0x93, 0x6b, /* 2 */ + 0x94, 0x7c, 0x95, 0x8a, 0x96, 0x99, 0x97, 0xa6, + 0x98, 0xb1, 0x99, 0xbc, 0x9a, 0xc6, 0x9b, 0xd0, + 0x9c, 0xdb, 0x9d, 0xe4, 0x9e, 0xed, 0x9f, 0xf6, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60, - 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E, - 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB, - 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5, + {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60, /* 3 */ + 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9e, + 0x98, 0xaa, 0x99, 0xb5, 0x9a, 0xbf, 0x9b, 0xcb, + 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55, + {0x90, 0x00, 0x91, 0x23, 0x92, 0x3f, 0x93, 0x55, /* 4 */ 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95, - 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6, - 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4, + 0x98, 0xa2, 0x99, 0xad, 0x9a, 0xb9, 0x9b, 0xc6, + 0x9c, 0xd2, 0x9d, 0xde, 0x9e, 0xe9, 0x9f, 0xf4, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48, + {0x90, 0x00, 0x91, 0x1b, 0x92, 0x33, 0x93, 0x48, /* 5 */ 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87, - 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE, - 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3, + 0x98, 0x96, 0x99, 0xa3, 0x9a, 0xb1, 0x9b, 0xbe, + 0x9c, 0xcc, 0x9d, 0xda, 0x9e, 0xe7, 0x9f, 0xf3, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20, + {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20, /* 6 */ 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67, 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa, 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26, - 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70, - 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0, - 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0, + {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26, /* 7 */ + 0x94, 0x38, 0x95, 0x4a, 0x96, 0x60, 0x97, 0x70, + 0x98, 0x80, 0x99, 0x90, 0x9a, 0xa0, 0x9b, 0xb0, + 0x9c, 0xc0, 0x9D, 0xd0, 0x9e, 0xe0, 0x9f, 0xf0, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35, - 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79, - 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6, - 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0, + {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35, /* 8 */ + 0x94, 0x47, 0x95, 0x5a, 0x96, 0x69, 0x97, 0x79, + 0x98, 0x88, 0x99, 0x97, 0x9a, 0xa7, 0x9b, 0xb6, + 0x9c, 0xc4, 0x9d, 0xd3, 0x9e, 0xe0, 0x9f, 0xf0, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40, + {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40, /* 9 */ 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84, 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44, - 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E, - 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4, - 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0, + {0x90, 0x00, 0x91, 0x18, 0x92, 0x2b, 0x93, 0x44, /* 10 */ + 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8e, + 0x98, 0x9c, 0x99, 0xaa, 0x9a, 0xb7, 0x9b, 0xc4, + 0x9c, 0xd0, 0x9d, 0xd8, 0x9e, 0xe2, 0x9f, 0xf0, + 0xa0, 0xff}, + {0x90, 0x00, 0x91, 0x1a, 0x92, 0x34, 0x93, 0x52, /* 11 */ + 0x94, 0x66, 0x95, 0x7e, 0x96, 0x8D, 0x97, 0x9B, + 0x98, 0xa8, 0x99, 0xb4, 0x9a, 0xc0, 0x9b, 0xcb, + 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52, - 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B, - 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB, - 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5, + {0x90, 0x00, 0x91, 0x3f, 0x92, 0x5a, 0x93, 0x6e, /* 12 */ + 0x94, 0x7f, 0x95, 0x8e, 0x96, 0x9c, 0x97, 0xa8, + 0x98, 0xb4, 0x99, 0xbf, 0x9a, 0xc9, 0x9b, 0xd3, + 0x9c, 0xdc, 0x9d, 0xe5, 0x9e, 0xee, 0x9f, 0xf6, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E, - 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8, - 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3, - 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6, - 0xA0, 0xFF}, - {0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83, - 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7, - 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC, - 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9, + {0x90, 0x00, 0x91, 0x54, 0x92, 0x6f, 0x93, 0x83, /* 13 */ + 0x94, 0x93, 0x95, 0xa0, 0x96, 0xad, 0x97, 0xb7, + 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdc, + 0x9c, 0xe4, 0x9d, 0xeb, 0x9e, 0xf2, 0x9f, 0xf9, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A, - 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6, - 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3, - 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA, + {0x90, 0x00, 0x91, 0x6e, 0x92, 0x88, 0x93, 0x9a, /* 14 */ + 0x94, 0xa8, 0x95, 0xb3, 0x96, 0xbd, 0x97, 0xc6, + 0x98, 0xcf, 0x99, 0xd6, 0x9a, 0xdd, 0x9b, 0xe3, + 0x9c, 0xe9, 0x9d, 0xef, 0x9e, 0xf4, 0x9f, 0xfa, 0xa0, 0xff}, - {0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7, - 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8, - 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED, - 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC, - 0xA0, 0xFF} + {0x90, 0x00, 0x91, 0x93, 0x92, 0xa8, 0x93, 0xb7, /* 15 */ + 0x94, 0xc1, 0x95, 0xca, 0x96, 0xd2, 0x97, 0xd8, + 0x98, 0xde, 0x99, 0xe3, 0x9a, 0xe8, 0x9b, 0xed, + 0x9c, 0xf1, 0x9d, 0xf5, 0x9e, 0xf8, 0x9f, 0xfc, + 0xa0, 0xff} }; static const __u8 tas5130a_sensor_init[][8] = { @@ -364,7 +366,7 @@ static const __u8 tas5130a_sensor_init[][8] = { }; /* read 1 byte */ -static int reg_r_1(struct gspca_dev *gspca_dev, +static int reg_r(struct gspca_dev *gspca_dev, __u16 index) { usb_control_msg(gspca_dev->dev, @@ -378,26 +380,26 @@ static int reg_r_1(struct gspca_dev *gspca_dev, } static void reg_w(struct gspca_dev *gspca_dev, - __u16 value, - __u16 index, - const __u8 *buffer, __u16 len) + __u16 index) +{ + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0, index, + NULL, 0, 500); +} + +static void i2c_w(struct gspca_dev *gspca_dev, + const __u8 *buffer, __u16 len) { - if (buffer == NULL) { - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, index, - NULL, 0, 500); - return; - } if (len <= USB_BUF_SZ) { memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, index, + 0x01, 0, gspca_dev->usb_buf, len, 500); } else { __u8 *tmpbuf; @@ -408,12 +410,56 @@ static void reg_w(struct gspca_dev *gspca_dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, index, + 0x01, 0, tmpbuf, len, 500); kfree(tmpbuf); } } +static void other_sensor_init(struct gspca_dev *gspca_dev) +{ + int i; + const __u8 *p; + __u8 byte; + __u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05}; + static const __u8 sensor_init[] = { + 0xdf, 0x6d, + 0xdd, 0x18, + 0x5a, 0xe0, + 0x5c, 0x07, + 0x5d, 0xb0, + 0x5e, 0x1e, + 0x60, 0x71, + 0xef, 0x00, + 0xe9, 0x00, + 0xea, 0x00, + 0x90, 0x24, + 0x91, 0xb2, + 0x82, 0x32, + 0xfd, 0x00, + 0xfd, 0x01, + 0xfd, 0x41, + 0x00 /* table end */ + }; + + p = sensor_init; + while (*p != 0) { + val[1] = *p++; + val[3] = *p++; + if (*p == 0) + reg_w(gspca_dev, 0x3c80); + i2c_w(gspca_dev, val, sizeof val); + i = 4; + while (--i >= 0) { + msleep(15); + byte = reg_r(gspca_dev, 0x60); + if (!(byte & 0x01)) + break; + } + } + reg_w(gspca_dev, 0x3c80); +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -430,7 +476,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; - sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value; + sd->gamma = GAMMA_DEF; sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value; sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value; sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value; @@ -439,27 +485,37 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -static int init_default_parameters(struct gspca_dev *gspca_dev) +static void setgamma(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(D_CONF, "Gamma: %d", sd->gamma); + i2c_w(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { /* some of this registers are not really neded, because * they are overriden by setbrigthness, setcontrast, etc, * but wont hurt anyway, and can help someone with similar webcam * to see the initial parameters.*/ - int i = 0; - __u8 test_byte; + struct sd *sd = (struct sd *) gspca_dev; + int i; + __u8 byte, test_byte; static const __u8 read_indexs[] = { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5, 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 }; - static const __u8 n1[6] = + static const __u8 n1[] = {0x08, 0x03, 0x09, 0x03, 0x12, 0x04}; - static const __u8 n2[2] = + static const __u8 n2[] = {0x08, 0x00}; - static const __u8 nset[6] = - { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 }; - static const __u8 n3[6] = + static const __u8 nset[] = + { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 }; + static const __u8 n3[] = {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04}; - static const __u8 n4[0x46] = + static const __u8 n4[] = {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c, 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68, 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1, @@ -469,44 +525,26 @@ static int init_default_parameters(struct gspca_dev *gspca_dev) 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68, 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40, 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46}; -#if 0 - static const __u8 nset1[50] = { - 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20, 0x8a, 0x5c, - 0x8b, 0x4c, 0x8c, 0x88, 0x8e, 0xb4, - 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x18, 0xa6, 0x4a, - 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08, - 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a, 0xbe, 0x36, - 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc0, - 0xc6, 0xd2 - }; -#endif - static const __u8 nset4[18] = { + static const __u8 nset4[] = { 0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8, 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8, 0xe8, 0xe0 }; /* ojo puede ser 0xe6 en vez de 0xe9 */ - static const __u8 nset2[20] = { + static const __u8 nset2[] = { 0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb, 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27, 0xd8, 0xc8, 0xd9, 0xfc }; - static const __u8 missing[8] = + static const __u8 missing[] = { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 }; - static const __u8 nset3[18] = { + static const __u8 nset3[] = { 0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8, 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8, 0xcf, 0xe0 }; - static const __u8 nset5[4] = - { 0x8f, 0x24, 0xc3, 0x00 }; /* bright */ - static const __u8 nset6[34] = { - 0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54, - 0x95, 0x65, 0x96, 0x75, 0x97, 0x84, - 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca, - 0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2, - 0xa0, 0xff - }; /* Gamma */ + static const __u8 nset5[] = + { 0x8f, 0x24, 0xc3, 0x00 }; /* bright */ static const __u8 nset7[4] = { 0x66, 0xca, 0xa8, 0xf8 }; /* 50/60 Hz */ static const __u8 nset9[4] = @@ -516,57 +554,74 @@ static int init_default_parameters(struct gspca_dev *gspca_dev) static const __u8 nset10[6] = { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 }; - reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06); - reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06); - reg_r_1(gspca_dev, 0x0063); - reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02); + byte = reg_r(gspca_dev, 0x06); + test_byte = reg_r(gspca_dev, 0x07); + if (byte == 0x08 && test_byte == 0x07) { + PDEBUG(D_CONF, "other sensor"); + sd->sensor = SENSOR_OTHER; + } else { + PDEBUG(D_CONF, "sensor %02x %02x", byte, test_byte); + sd->sensor = SENSOR_TAS5130A; + } + + i2c_w(gspca_dev, n1, sizeof n1); + test_byte = 0; + i = 5; + while (--i >= 0) { + i2c_w(gspca_dev, nset, sizeof nset); + msleep(5); + test_byte = reg_r(gspca_dev, 0x0063); + msleep(100); + if (test_byte == 0x17) + break; /* OK */ + } + if (i < 0) { + err("Bad sensor reset %02x", test_byte); +/* return -EIO; */ +/*fixme: test - continue */ + } + i2c_w(gspca_dev, n2, sizeof n2); + i = 0; while (read_indexs[i] != 0x00) { - test_byte = reg_r_1(gspca_dev, read_indexs[i]); - PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i], + test_byte = reg_r(gspca_dev, read_indexs[i]); + PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i], test_byte); i++; } - reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06); - reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46); - reg_r_1(gspca_dev, 0x0080); - reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0); - reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14); - reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12); - reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12); - reg_w(gspca_dev, 0x00, 0x3880, NULL, 0); - reg_w(gspca_dev, 0x00, 0x3880, NULL, 0); - reg_w(gspca_dev, 0x00, 0x338e, NULL, 0); - reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04); - reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0); - reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22); - reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0); - reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0); - - reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08); - - reg_w(gspca_dev, 0x00, 0x2087, NULL, 0); - reg_w(gspca_dev, 0x00, 0x2088, NULL, 0); - reg_w(gspca_dev, 0x00, 0x2089, NULL, 0); - - reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04); - reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06); - reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06); - reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04); - - reg_w(gspca_dev, 0x00, 0x2880, NULL, 0); - reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14); - reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12); - reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12); - - return 0; -} + i2c_w(gspca_dev, n3, sizeof n3); + i2c_w(gspca_dev, n4, sizeof n4); + reg_r(gspca_dev, 0x0080); + reg_w(gspca_dev, 0x2c80); + i2c_w(gspca_dev, nset2, sizeof nset2); + i2c_w(gspca_dev, nset3, sizeof nset3); + i2c_w(gspca_dev, nset4, sizeof nset4); + reg_w(gspca_dev, 0x3880); + reg_w(gspca_dev, 0x3880); + reg_w(gspca_dev, 0x338e); + i2c_w(gspca_dev, nset5, sizeof nset5); + reg_w(gspca_dev, 0x00a9); + setgamma(gspca_dev); + reg_w(gspca_dev, 0x86bb); + reg_w(gspca_dev, 0x4aa6); + + i2c_w(gspca_dev, missing, sizeof missing); + + reg_w(gspca_dev, 0x2087); + reg_w(gspca_dev, 0x2088); + reg_w(gspca_dev, 0x2089); + + i2c_w(gspca_dev, nset7, sizeof nset7); + i2c_w(gspca_dev, nset10, sizeof nset10); + i2c_w(gspca_dev, nset8, sizeof nset8); + i2c_w(gspca_dev, nset9, sizeof nset9); + + reg_w(gspca_dev, 0x2880); + i2c_w(gspca_dev, nset2, sizeof nset2); + i2c_w(gspca_dev, nset3, sizeof nset3); + i2c_w(gspca_dev, nset4, sizeof nset4); -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - init_default_parameters(gspca_dev); return 0; } @@ -574,37 +629,36 @@ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; unsigned int brightness; - __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 }; - brightness = sd->brightness; + __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x00 }; + brightness = sd->brightness; if (brightness < 7) { - set6[3] = 0x70 - (brightness * 0xa); + set6[3] = 0x70 - brightness * 0x10; } else { set6[1] = 0x24; - set6[3] = 0x00 + ((brightness - 7) * 0xa); + set6[3] = 0x00 + ((brightness - 7) * 0x10); } - reg_w(gspca_dev, 0x01, 0x0000, set6, 4); + i2c_w(gspca_dev, set6, sizeof set6); } static void setflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 flipcmd[8] = - { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 }; + {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}; - if (sd->mirror == 1) + if (sd->mirror) flipcmd[3] = 0x01; - reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8); + i2c_w(gspca_dev, flipcmd, sizeof flipcmd); } static void seteffect(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06); + i2c_w(gspca_dev, effects_table[sd->effect], sizeof effects_table[0]); if (sd->effect == 1 || sd->effect == 5) { PDEBUG(D_CONF, "This effect have been disabled for webcam \"safety\""); @@ -612,9 +666,9 @@ static void seteffect(struct gspca_dev *gspca_dev) } if (sd->effect == 1 || sd->effect == 4) - reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0); + reg_w(gspca_dev, 0x4aa6); else - reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0); + reg_w(gspca_dev, 0xfaa6); } static void setwhitebalance(struct gspca_dev *gspca_dev) @@ -627,7 +681,7 @@ static void setwhitebalance(struct gspca_dev *gspca_dev) if (sd->whitebalance == 1) white_balance[7] = 0x3c; - reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8); + i2c_w(gspca_dev, white_balance, sizeof white_balance); } static void setlightfreq(struct gspca_dev *gspca_dev) @@ -638,21 +692,21 @@ static void setlightfreq(struct gspca_dev *gspca_dev) if (sd->freq == 2) /* 60hz */ freq[1] = 0x00; - reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4); + i2c_w(gspca_dev, freq, sizeof freq); } static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; unsigned int contrast = sd->contrast; - __u16 reg_to_write = 0x00; + __u16 reg_to_write; if (contrast < 7) reg_to_write = 0x8ea9 - (0x200 * contrast); else reg_to_write = (0x00a9 + ((contrast - 7) * 0x200)); - reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0); + reg_w(gspca_dev, reg_to_write); } static void setcolors(struct gspca_dev *gspca_dev) @@ -661,29 +715,113 @@ static void setcolors(struct gspca_dev *gspca_dev) __u16 reg_to_write; reg_to_write = 0xc0bb + sd->colors * 0x100; - reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0); + reg_w(gspca_dev, reg_to_write); } -static void setgamma(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev) { -#if 0 struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; + __u16 reg_to_write; - PDEBUG(D_CONF, "Gamma: %d", sd->gamma); + reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness; - reg_w(gspca_dev, 0x01, 0x0000, gamma_table[sd->gamma], 34); -#endif + reg_w(gspca_dev, reg_to_write); } -static void setsharpness(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u16 reg_to_write; + int i, mode; + static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 }; + __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 }; + static const __u8 t3[] = + { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06, + 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 }; + static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 }; - reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness; + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv; + switch (mode) { + case 1: /* 352x288 */ + t2[1] = 0x40; + break; + case 2: /* 320x240 */ + t2[1] = 0x10; + break; + case 3: /* 176x144 */ + t2[1] = 0x50; + break; + case 4: /* 160x120 */ + t2[1] = 0x20; + break; + default: /* 640x480 (0x00) */ + break; + } + + if (sd->sensor == SENSOR_TAS5130A) { + i = 0; + while (tas5130a_sensor_init[i][0] != 0) { + i2c_w(gspca_dev, tas5130a_sensor_init[i], + sizeof tas5130a_sensor_init[0]); + i++; + } + reg_w(gspca_dev, 0x3c80); + /* just in case and to keep sync with logs (for mine) */ + i2c_w(gspca_dev, tas5130a_sensor_init[3], + sizeof tas5130a_sensor_init[0]); + reg_w(gspca_dev, 0x3c80); + } else { + other_sensor_init(gspca_dev); + } + /* just in case and to keep sync with logs (for mine) */ + i2c_w(gspca_dev, t1, sizeof t1); + i2c_w(gspca_dev, t2, sizeof t2); + reg_r(gspca_dev, 0x0012); + i2c_w(gspca_dev, t3, sizeof t3); + reg_w(gspca_dev, 0x0013); + i2c_w(gspca_dev, t4, sizeof t4); + /* restart on each start, just in case, sometimes regs goes wrong + * when using controls from app */ + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); +#if 0 + seteffect(gspca_dev); + setflip(gspca_dev); +#endif + return 0; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + static __u8 ffd9[] = { 0xff, 0xd9 }; - reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0); + if (data[0] == 0x5a) { + /* Control Packet, after this came the header again, + * but extra bytes came in the packet before this, + * sometimes an EOF arrives, sometimes not... */ + return; + } + data += 2; + len -= 2; + if (data[0] == 0xff && data[1] == 0xd8) { + /* extra bytes....., could be processed too but would be + * a waste of time, right now leave the application and + * libjpeg do it for ourserlves.. */ + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + ffd9, 2); + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); + return; + } + + if (data[len - 2] == 0xff && data[len - 1] == 0xd9) { + /* Just in case, i have seen packets with the marker, + * other's do not include it... */ + len -= 2; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) @@ -807,6 +945,7 @@ static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val) static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; + *val = sd->gamma; return 0; } @@ -854,9 +993,9 @@ static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val) sd->autogain = val; if (val != 0) - reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0); + reg_w(gspca_dev, 0xf48e); else - reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0); + reg_w(gspca_dev, 0xb48e); return 0; } @@ -868,103 +1007,6 @@ static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) -{ - int mode; - - static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 }; - __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 }; - static const __u8 t3[] = - { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06, - 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 }; - static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 }; - - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv; - switch (mode) { - case 1: /* 352x288 */ - t2[1] = 0x40; - break; - case 2: /* 320x240 */ - t2[1] = 0x10; - break; - case 3: /* 176x144 */ - t2[1] = 0x50; - break; - case 4: /* 160x120 */ - t2[1] = 0x20; - break; - default: /* 640x480 (0x00) */ - break; - } - - reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8); - reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8); - reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8); - reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8); - reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0); - /* just in case and to keep sync with logs (for mine) */ - reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8); - reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0); - /* just in case and to keep sync with logs (for mine) */ - reg_w(gspca_dev, 0x01, 0x0000, t1, 4); - reg_w(gspca_dev, 0x01, 0x0000, t2, 6); - reg_r_1(gspca_dev, 0x0012); - reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10); - reg_w(gspca_dev, 0x00, 0x0013, NULL, 0); - reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4); - /* restart on each start, just in case, sometimes regs goes wrong - * when using controls from app */ - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); -#if 0 - seteffect(gspca_dev); - setflip(gspca_dev); -#endif -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - struct gspca_frame *frame, /* target */ - __u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - int sof = 0; - static __u8 ffd9[] = { 0xff, 0xd9 }; - - if (data[0] == 0x5a) { - /* Control Packet, after this came the header again, - * but extra bytes came in the packet before this, - * sometimes an EOF arrives, sometimes not... */ - return; - } - - if (data[len - 1] == 0xff && data[len] == 0xd9) { - /* Just in case, i have seen packets with the marker, - * other's do not include it... */ - data += 2; - len -= 4; - } else if (data[2] == 0xff && data[3] == 0xd8) { - sof = 1; - data += 2; - len -= 2; - } else { - data += 2; - len -= 2; - } - - if (sof) { - /* extra bytes....., could be processed too but would be - * a waste of time, right now leave the application and - * libjpeg do it for ourserlves.. */ - frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, - ffd9, 2); - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); - return; - } - - gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c index 01de48d4e..8204dabb1 100644 --- a/linux/drivers/media/video/gspca/tv8532.c +++ b/linux/drivers/media/video/gspca/tv8532.c @@ -390,7 +390,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) } /* -- start the camera -- */ -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); @@ -443,6 +443,7 @@ static void sd_start(struct gspca_dev *gspca_dev) /************************************************/ tv_8532_PollReg(gspca_dev); reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index cfb66c257..95531138e 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -1698,7 +1698,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev) usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]); } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; const __u8 *GammaT = NULL; @@ -1782,7 +1782,7 @@ static void sd_start(struct gspca_dev *gspca_dev) break; default: PDEBUG(D_PROBE, "Damned !! no sensor found Bye"); - return; + return -EMEDIUMTYPE; } if (GammaT && MatrixT) { put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a); @@ -1818,6 +1818,7 @@ static void sd_start(struct gspca_dev *gspca_dev) setautogain(gspca_dev); setlightfreq(gspca_dev); } + return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index 3153bd4cd..0b1871cec 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -7183,7 +7183,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void sd_start(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; @@ -7336,6 +7336,7 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w(dev, 0x02, 0x0008); break; } + return 0; } static void sd_stop0(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c index 3f1d7a660..9a5662024 100644 --- a/linux/drivers/media/video/ov511.c +++ b/linux/drivers/media/video/ov511.c @@ -974,14 +974,14 @@ dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) for (i = reg1; i <= regn; i++) { rc = i2c_r(ov, i); - info("Sensor[0x%02X] = 0x%02X", i, rc); + dev_info(&ov->dev->dev, "Sensor[0x%02X] = 0x%02X\n", i, rc); } } static void dump_i2c_regs(struct usb_ov511 *ov) { - info("I2C REGS"); + dev_info(&ov->dev->dev, "I2C REGS\n"); dump_i2c_range(ov, 0x00, 0x7C); } @@ -992,28 +992,28 @@ dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) for (i = reg1; i <= regn; i++) { rc = reg_r(ov, i); - info("OV511[0x%02X] = 0x%02X", i, rc); + dev_info(&ov->dev->dev, "OV511[0x%02X] = 0x%02X\n", i, rc); } } static void ov511_dump_regs(struct usb_ov511 *ov) { - info("CAMERA INTERFACE REGS"); + dev_info(&ov->dev->dev, "CAMERA INTERFACE REGS\n"); dump_reg_range(ov, 0x10, 0x1f); - info("DRAM INTERFACE REGS"); + dev_info(&ov->dev->dev, "DRAM INTERFACE REGS\n"); dump_reg_range(ov, 0x20, 0x23); - info("ISO FIFO REGS"); + dev_info(&ov->dev->dev, "ISO FIFO REGS\n"); dump_reg_range(ov, 0x30, 0x31); - info("PIO REGS"); + dev_info(&ov->dev->dev, "PIO REGS\n"); dump_reg_range(ov, 0x38, 0x39); dump_reg_range(ov, 0x3e, 0x3e); - info("I2C REGS"); + dev_info(&ov->dev->dev, "I2C REGS\n"); dump_reg_range(ov, 0x40, 0x49); - info("SYSTEM CONTROL REGS"); + dev_info(&ov->dev->dev, "SYSTEM CONTROL REGS\n"); dump_reg_range(ov, 0x50, 0x55); dump_reg_range(ov, 0x5e, 0x5f); - info("OmniCE REGS"); + dev_info(&ov->dev->dev, "OmniCE REGS\n"); dump_reg_range(ov, 0x70, 0x79); /* NOTE: Quantization tables are not readable. You will get the value * in reg. 0x79 for every table register */ @@ -1025,25 +1025,25 @@ ov511_dump_regs(struct usb_ov511 *ov) static void ov518_dump_regs(struct usb_ov511 *ov) { - info("VIDEO MODE REGS"); + dev_info(&ov->dev->dev, "VIDEO MODE REGS\n"); dump_reg_range(ov, 0x20, 0x2f); - info("DATA PUMP AND SNAPSHOT REGS"); + dev_info(&ov->dev->dev, "DATA PUMP AND SNAPSHOT REGS\n"); dump_reg_range(ov, 0x30, 0x3f); - info("I2C REGS"); + dev_info(&ov->dev->dev, "I2C REGS\n"); dump_reg_range(ov, 0x40, 0x4f); - info("SYSTEM CONTROL AND VENDOR REGS"); + dev_info(&ov->dev->dev, "SYSTEM CONTROL AND VENDOR REGS\n"); dump_reg_range(ov, 0x50, 0x5f); - info("60 - 6F"); + dev_info(&ov->dev->dev, "60 - 6F\n"); dump_reg_range(ov, 0x60, 0x6f); - info("70 - 7F"); + dev_info(&ov->dev->dev, "70 - 7F\n"); dump_reg_range(ov, 0x70, 0x7f); - info("Y QUANTIZATION TABLE"); + dev_info(&ov->dev->dev, "Y QUANTIZATION TABLE\n"); dump_reg_range(ov, 0x80, 0x8f); - info("UV QUANTIZATION TABLE"); + dev_info(&ov->dev->dev, "UV QUANTIZATION TABLE\n"); dump_reg_range(ov, 0x90, 0x9f); - info("A0 - BF"); + dev_info(&ov->dev->dev, "A0 - BF\n"); dump_reg_range(ov, 0xa0, 0xbf); - info("CBR"); + dev_info(&ov->dev->dev, "CBR\n"); dump_reg_range(ov, 0xc0, 0xcf); } #endif @@ -3205,9 +3205,10 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) */ if (printph) { - info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", - pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], - in[7], in[8], in[9], in[10], in[11]); + dev_info(&ov->dev->dev, + "ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", + pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], + in[7], in[8], in[9], in[10], in[11]); } /* Check for SOF/EOF packet */ @@ -3366,8 +3367,10 @@ ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) * the definitive SOF/EOF format */ if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) { if (printph) { - info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0], - in[1], in[2], in[3], in[4], in[5], in[6], in[7]); + dev_info(&ov->dev->dev, + "ph: %2x %2x %2x %2x %2x %2x %2x %2x\n", + in[0], in[1], in[2], in[3], in[4], in[5], + in[6], in[7]); } if (frame->scanstate == STATE_LINES) { @@ -3650,14 +3653,16 @@ ov51x_init_isoc(struct usb_ov511 *ov) if (packetsize == -1) { ov518_set_packet_size(ov, 640); } else { - info("Forcing packet size to %d", packetsize); + dev_info(&ov->dev->dev, "Forcing packet size to %d\n", + packetsize); ov518_set_packet_size(ov, packetsize); } } else { if (packetsize == -1) { ov511_set_packet_size(ov, size); } else { - info("Forcing packet size to %d", packetsize); + dev_info(&ov->dev->dev, "Forcing packet size to %d\n", + packetsize); ov511_set_packet_size(ov, packetsize); } } @@ -4125,7 +4130,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, return -EIO; if (force_palette && p->palette != force_palette) { - info("Palette rejected (%s)", + dev_info(&ov->dev->dev, "Palette rejected (%s)\n", symbolic(v4l1_plist, p->palette)); return -EINVAL; } @@ -4853,26 +4858,27 @@ ov7xx0_configure(struct usb_ov511 *ov) err("Error detecting sensor type"); return -1; } else if ((rc & 3) == 3) { - info("Sensor is an OV7610"); + dev_info(&ov->dev->dev, "Sensor is an OV7610\n"); ov->sensor = SEN_OV7610; } else if ((rc & 3) == 1) { /* I don't know what's different about the 76BE yet. */ if (i2c_r(ov, 0x15) & 1) - info("Sensor is an OV7620AE"); + dev_info(&ov->dev->dev, "Sensor is an OV7620AE\n"); else - info("Sensor is an OV76BE"); + dev_info(&ov->dev->dev, "Sensor is an OV76BE\n"); /* OV511+ will return all zero isoc data unless we * configure the sensor as a 7620. Someone needs to * find the exact reg. setting that causes this. */ if (ov->bridge == BRG_OV511PLUS) { - info("Enabling 511+/7620AE workaround"); + dev_info(&ov->dev->dev, + "Enabling 511+/7620AE workaround\n"); ov->sensor = SEN_OV7620; } else { ov->sensor = SEN_OV76BE; } } else if ((rc & 3) == 0) { - info("Sensor is an OV7620"); + dev_info(&ov->dev->dev, "Sensor is an OV7620\n"); ov->sensor = SEN_OV7620; } else { err("Unknown image sensor version: %d", rc & 3); @@ -5028,16 +5034,16 @@ ov6xx0_configure(struct usb_ov511 *ov) if ((rc & 3) == 0) { ov->sensor = SEN_OV6630; - info("Sensor is an OV6630"); + dev_info(&ov->dev->dev, "Sensor is an OV6630\n"); } else if ((rc & 3) == 1) { ov->sensor = SEN_OV6620; - info("Sensor is an OV6620"); + dev_info(&ov->dev->dev, "Sensor is an OV6620\n"); } else if ((rc & 3) == 2) { ov->sensor = SEN_OV6630; - info("Sensor is an OV6630AE"); + dev_info(&ov->dev->dev, "Sensor is an OV6630AE\n"); } else if ((rc & 3) == 3) { ov->sensor = SEN_OV6630; - info("Sensor is an OV6630AF"); + dev_info(&ov->dev->dev, "Sensor is an OV6630AF\n"); } /* Set sensor-specific vars */ @@ -5092,10 +5098,10 @@ ks0127_configure(struct usb_ov511 *ov) err("Error detecting sensor type"); return -1; } else if ((rc & 0x0f) == 0) { - info("Sensor is a KS0127"); + dev_info(&ov->dev->dev, "Sensor is a KS0127\n"); ov->sensor = SEN_KS0127; } else if ((rc & 0x0f) == 9) { - info("Sensor is a KS0127B Rev. A"); + dev_info(&ov->dev->dev, "Sensor is a KS0127B Rev. A\n"); ov->sensor = SEN_KS0127B; } } else { @@ -5204,7 +5210,8 @@ saa7111a_configure(struct usb_ov511 *ov) err("Error detecting sensor version"); return -1; } else { - info("Sensor is an SAA7111A (version 0x%x)", rc); + dev_info(&ov->dev->dev, + "Sensor is an SAA7111A (version 0x%x)\n", rc); ov->sensor = SEN_SAA7111A; } @@ -5266,7 +5273,7 @@ ov511_configure(struct usb_ov511 *ov) PDEBUG (1, "CustomID = %d", ov->customid); ov->desc = symbolic(camlist, ov->customid); - info("model: %s", ov->desc); + dev_info(&ov->dev->dev, "model: %s\n", ov->desc); if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) { err("Camera type (%d) not recognized", ov->customid); @@ -5430,7 +5437,8 @@ ov518_configure(struct usb_ov511 *ov) PDEBUG(4, ""); /* First 5 bits of custom ID reg are a revision ID on OV518 */ - info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); + dev_info(&ov->dev->dev, "Device revision %d\n", + 0x1F & reg_r(ov, R511_SYS_CUST_ID)); /* Give it the default description */ ov->desc = symbolic(camlist, 0); @@ -5777,7 +5785,8 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } - info("USB %s video device found", symbolic(brglist, ov->bridge)); + dev_info(&intf->dev, "USB %s video device found\n", + symbolic(brglist, ov->bridge)); init_waitqueue_head(&ov->wq); @@ -5858,8 +5867,8 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } - info("Device at %s registered to minor %d", ov->usb_path, - ov->vdev->minor); + dev_info(&intf->dev, "Device at %s registered to minor %d\n", + ov->usb_path, ov->vdev->minor); usb_set_intfdata(intf, ov); if (ov_create_sysfs(ov->vdev)) { @@ -5962,7 +5971,8 @@ usb_ov511_init(void) if (retval) goto out; - info(DRIVER_VERSION " : " DRIVER_DESC); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); out: return retval; @@ -5972,8 +5982,7 @@ static void __exit usb_ov511_exit(void) { usb_deregister(&ov511_driver); - info("driver deregistered"); - + printk(KERN_INFO KBUILD_MODNAME ": driver deregistered\n"); } module_init(usb_ov511_init); diff --git a/linux/drivers/media/video/ov511.h b/linux/drivers/media/video/ov511.h index eba9f2e64..c303ac5a8 100644 --- a/linux/drivers/media/video/ov511.h +++ b/linux/drivers/media/video/ov511.h @@ -13,7 +13,8 @@ #ifdef OV511_DEBUG #define PDEBUG(level, fmt, args...) \ - if (debug >= (level)) info("[%s:%d] " fmt, \ + if (debug >= (level)) \ + printk(KERN_INFO KBUILD_MODNAME "[%s:%d] \n" fmt, \ __func__, __LINE__ , ## args) #else #define PDEBUG(level, fmt, args...) do {} while(0) diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c index 9a3ad0905..2399959a8 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -138,9 +138,11 @@ static int __init pvr_init(void) ret = usb_register(&pvr_driver); if (ret == 0) - info(DRIVER_DESC " : " DRIVER_VERSION); - if (pvrusb2_debug) info("Debug mask is %d (0x%x)", - pvrusb2_debug,pvrusb2_debug); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); + if (pvrusb2_debug) + printk(KERN_INFO KBUILD_MODNAME ": Debug mask is %d (0x%x)\n", + pvrusb2_debug,pvrusb2_debug); pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete"); diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 135250cf5..de0c8a153 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -4566,7 +4566,7 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .tv = 1, .gpio = 0x624000, - }, { + }, { .name = name_comp1, .vmux = 1, .amux = LINE1, @@ -4603,14 +4603,48 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, }, { .name = name_comp, - .vmux = 4, - .amux = LINE1, + .vmux = 4, + .amux = LINE1, }, { .name = name_svideo, .vmux = 8, .amux = LINE1, } }, }, + [SAA7134_BOARD_ASUSTeK_TIGER] = { + .name = "Asus Tiger Rev:1.00", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 0, + .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 0x0200000, + .inputs = { { + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE2, + }, { + .name = name_comp2, + .vmux = 0, + .amux = LINE2, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -5397,8 +5431,8 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1043, - .subdevice = 0x4857, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, + .subdevice = 0x4857, /* REV:1.00 */ + .driver_data = SAA7134_BOARD_ASUSTeK_TIGER, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -6280,6 +6314,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_KWORLD_DVBT_210: case SAA7134_BOARD_TEVION_DVBT_220RF: + case SAA7134_BOARD_ASUSTeK_TIGER: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index 5222f1728..c84895fca 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -1339,6 +1339,11 @@ static int dvb_init(struct saa7134_dev *dev) } } break; + case SAA7134_BOARD_ASUSTeK_TIGER: + if (configure_tda827x_fe(dev, &philips_tiger_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; + break; default: wprintk("Huh? unknown DVB card?\n"); break; diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index b704b5f40..502cbe60c 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -275,6 +275,7 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_M135A 149 #define SAA7134_BOARD_REAL_ANGEL_220 150 #define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151 +#define SAA7134_BOARD_ASUSTeK_TIGER 152 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 diff --git a/linux/drivers/media/video/se401.c b/linux/drivers/media/video/se401.c index 4b55b7dd7..5a346d0c5 100644 --- a/linux/drivers/media/video/se401.c +++ b/linux/drivers/media/video/se401.c @@ -292,7 +292,7 @@ static void se401_button_irq(struct urb *urb) int status; if (!se401->dev) { - info("ohoh: device vapourished"); + dev_info(&urb->dev->dev, "device vapourished\n"); return; } @@ -336,7 +336,7 @@ static void se401_video_irq(struct urb *urb) return; if (!se401->dev) { - info ("ohoh: device vapourished"); + dev_info(&urb->dev->dev, "device vapourished\n"); return; } @@ -383,7 +383,7 @@ static void se401_video_irq(struct urb *urb) urb->status=0; urb->dev=se401->dev; if(usb_submit_urb(urb, GFP_KERNEL)) - info("urb burned down"); + dev_info(&urb->dev->dev, "urb burned down\n"); return; } @@ -868,7 +868,8 @@ static int se401_newframe(struct usb_se401 *se401, int framenr) ); if (se401->nullpackets > SE401_MAX_NULLPACKETS) { se401->nullpackets=0; - info("to many null length packets, restarting capture"); + dev_info(&se401->dev->dev, + "too many null length packets, restarting capture\n"); se401_stop_stream(se401); se401_start_stream(se401); } else { @@ -888,7 +889,8 @@ static int se401_newframe(struct usb_se401 *se401, int framenr) se401->scratch_use=0; if (errors > SE401_MAX_ERRORS) { errors=0; - info("to much errors, restarting capture"); + dev_info(&se401->dev->dev, + "too many errors, restarting capture\n"); se401_stop_stream(se401); se401_start_stream(se401); } @@ -921,7 +923,7 @@ static void usb_se401_remove_disconnected (struct usb_se401 *se401) usb_kill_urb(se401->inturb); usb_free_urb(se401->inturb); } - info("%s disconnected", se401->camera_name); + dev_info(&se401->dev->dev, "%s disconnected", se401->camera_name); /* Free the memory */ kfree(se401->width); @@ -968,8 +970,8 @@ static int se401_close(struct inode *inode, struct file *file) rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES); if (se401->removed) { + dev_info(&se401->dev->dev, "device unregistered\n"); usb_se401_remove_disconnected(se401); - info("device unregistered"); } else { for (i=0; i<SE401_NUMFRAMES; i++) se401->frame[i].grabstate=FRAME_UNUSED; @@ -1284,7 +1286,7 @@ static int se401_init(struct usb_se401 *se401, int button) for (i=0; i<se401->sizes; i++) { sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]); } - info("%s", temp); + dev_info(&se401->dev->dev, "%s\n", temp); se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3; rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); @@ -1318,7 +1320,8 @@ static int se401_init(struct usb_se401 *se401, int button) if (button) { se401->inturb=usb_alloc_urb(0, GFP_KERNEL); if (!se401->inturb) { - info("Allocation of inturb failed"); + dev_info(&se401->dev->dev, + "Allocation of inturb failed\n"); return 1; } usb_fill_int_urb(se401->inturb, se401->dev, @@ -1329,7 +1332,7 @@ static int se401_init(struct usb_se401 *se401, int button) 8 ); if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { - info("int urb burned down"); + dev_info(&se401->dev->dev, "int urb burned down\n"); return 1; } } else @@ -1386,7 +1389,7 @@ static int se401_probe(struct usb_interface *intf, return -ENODEV; /* We found one */ - info("SE401 camera found: %s", camera_name); + dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name); if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { err("couldn't kmalloc se401 struct"); @@ -1397,7 +1400,8 @@ static int se401_probe(struct usb_interface *intf, se401->iface = interface->bInterfaceNumber; se401->camera_name = camera_name; - info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255); + dev_info(&intf->dev, "firmware version: %02x\n", + le16_to_cpu(dev->descriptor.bcdDevice) & 255); if (se401_init(se401, button)) { kfree(se401); @@ -1415,7 +1419,8 @@ static int se401_probe(struct usb_interface *intf, err("video_register_device failed"); return -EIO; } - info("registered new video device: video%d", se401->vdev.minor); + dev_info(&intf->dev, "registered new video device: video%d\n", + se401->vdev.minor); usb_set_intfdata (intf, se401); return 0; @@ -1459,10 +1464,10 @@ static struct usb_driver se401_driver = { static int __init usb_se401_init(void) { - info("SE401 usb camera driver version %s registering", version); + printk(KERN_INFO "SE401 usb camera driver version %s registering\n", version); if (flickerless) if (flickerless!=50 && flickerless!=60) { - info("Invallid flickerless value, use 0, 50 or 60."); + printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n"); return -1; } return usb_register(&se401_driver); @@ -1471,7 +1476,7 @@ static int __init usb_se401_init(void) static void __exit usb_se401_exit(void) { usb_deregister(&se401_driver); - info("SE401 driver deregistered"); + printk(KERN_INFO "SE401 driver deregistered\frame"); } module_init(usb_se401_init); diff --git a/linux/drivers/media/video/stv680.c b/linux/drivers/media/video/stv680.c index 8df48a547..f74c08b41 100644 --- a/linux/drivers/media/video/stv680.c +++ b/linux/drivers/media/video/stv680.c @@ -85,7 +85,8 @@ static unsigned int debug; #define PDEBUG(level, fmt, args...) \ do { \ if (debug >= level) \ - info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \ + printk(KERN_INFO KBUILD_MODNAME " [%s:%d] \n" fmt, \ + __func__, __LINE__ , ## args); \ } while (0) @@ -1557,7 +1558,8 @@ static int __init usb_stv680_init (void) } PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); - info(DRIVER_DESC " " DRIVER_VERSION); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); return 0; } diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c index 53ece95db..7e670f2bc 100644 --- a/linux/drivers/media/video/tvaudio.c +++ b/linux/drivers/media/video/tvaudio.c @@ -1804,7 +1804,7 @@ static int chip_command(struct i2c_client *client, break; case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ - if (desc->checkmode) { + if (desc->checkmode && desc->setmode) { desc->setmode(chip,V4L2_TUNER_MODE_MONO); if (chip->prevmode != V4L2_TUNER_MODE_MONO) chip->prevmode = -1; /* reset previous mode */ diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c index 697e74a24..d202feac0 100644 --- a/linux/drivers/media/video/usbvideo/ibmcam.c +++ b/linux/drivers/media/video/usbvideo/ibmcam.c @@ -258,7 +258,9 @@ static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame h (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00)) { #if 0 /* keep */ /* This code helps to detect new frame markers */ - info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3)); + dev_info(&uvd->dev->dev, + "Header sig: 00 FF 00 %02X\n", + RING_QUEUE_PEEK(&uvd->dp, 3)); #endif frame->header = RING_QUEUE_PEEK(&uvd->dp, 3); if ((frame->header == HDRSIG_MODEL1_128x96) || @@ -266,7 +268,8 @@ static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame h (frame->header == HDRSIG_MODEL1_352x288)) { #if 0 /* keep */ - info("Header found."); + dev_info(&uvd->dev->dev, + "Header found.\n"); #endif RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); icam->has_hdr = 1; @@ -295,7 +298,7 @@ case IBMCAM_MODEL_4: (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF)) { #if 0 /* keep */ - info("Header found."); + dev_info(&uvd->dev->dev, "Header found.\n"); #endif RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); icam->has_hdr = 1; @@ -338,7 +341,7 @@ case IBMCAM_MODEL_4: byte4 = RING_QUEUE_PEEK(&uvd->dp, 3); frame->header = (byte3 << 8) | byte4; #if 0 /* keep */ - info("Header found."); + dev_info(&uvd->dev->dev, "Header found.\n"); #endif RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); icam->has_hdr = 1; @@ -354,7 +357,8 @@ case IBMCAM_MODEL_4: } if (!icam->has_hdr) { if (uvd->debug > 2) - info("Skipping frame, no header"); + dev_info(&uvd->dev->dev, + "Skipping frame, no header\n"); return scan_EndParse; } @@ -881,7 +885,9 @@ static enum ParseState ibmcam_model3_parse_lines( */ if ((frame->curline + 1) >= data_h) { if (uvd->debug >= 3) - info("Reached line %d. (frame is done)", frame->curline); + dev_info(&uvd->dev->dev, + "Reached line %d. (frame is done)\n", + frame->curline); return scan_NextFrame; } @@ -954,8 +960,9 @@ static enum ParseState ibmcam_model3_parse_lines( if (frame->curline >= VIDEOSIZE_Y(frame->request)) { if (uvd->debug >= 3) { - info("All requested lines (%ld.) done.", - VIDEOSIZE_Y(frame->request)); + dev_info(&uvd->dev->dev, + "All requested lines (%ld.) done.\n", + VIDEOSIZE_Y(frame->request)); } return scan_NextFrame; } else @@ -1000,7 +1007,9 @@ static enum ParseState ibmcam_model4_128x96_parse_lines( */ if ((frame->curline + 1) >= data_h) { if (uvd->debug >= 3) - info("Reached line %d. (frame is done)", frame->curline); + dev_info(&uvd->dev->dev, + "Reached line %d. (frame is done)\n", + frame->curline); return scan_NextFrame; } @@ -1049,8 +1058,9 @@ static enum ParseState ibmcam_model4_128x96_parse_lines( if (frame->curline >= VIDEOSIZE_Y(frame->request)) { if (uvd->debug >= 3) { - info("All requested lines (%ld.) done.", - VIDEOSIZE_Y(frame->request)); + dev_info(&uvd->dev->dev, + "All requested lines (%ld.) done.\n", + VIDEOSIZE_Y(frame->request)); } return scan_NextFrame; } else @@ -1171,10 +1181,11 @@ static int ibmcam_veio( sizeof(cp), 1000); #if 0 /* keep */ - info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " - "(req=$%02x val=$%04x ind=$%04x)", - cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], - req, value, index); + dev_info(&uvd->dev->dev, + "USB => %02x%02x%02x%02x%02x%02x%02x%02x " + "(req=$%02x val=$%04x ind=$%04x)\n", + cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], + req, value, index); #endif } else { i = usb_control_msg( @@ -1449,10 +1460,9 @@ static void ibmcam_adjust_contrast(struct uvd *uvd) */ static void ibmcam_change_lighting_conditions(struct uvd *uvd) { - static const char proc[] = "ibmcam_change_lighting_conditions"; - if (debug > 0) - info("%s: Set lighting to %hu.", proc, lighting); + dev_info(&uvd->dev->dev, + "%s: Set lighting to %hu.\n", __func__, lighting); switch (IBMCAM_T(uvd)->camera_model) { case IBMCAM_MODEL_1: @@ -1495,8 +1505,6 @@ static void ibmcam_change_lighting_conditions(struct uvd *uvd) */ static void ibmcam_set_sharpness(struct uvd *uvd) { - static const char proc[] = "ibmcam_set_sharpness"; - switch (IBMCAM_T(uvd)->camera_model) { case IBMCAM_MODEL_1: { @@ -1505,7 +1513,8 @@ static void ibmcam_set_sharpness(struct uvd *uvd) RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); if (debug > 0) - info("%s: Set sharpness to %hu.", proc, sharpness); + dev_info(&uvd->dev->dev, "%s: Set sharpness to %hu.\n", + __func__, sharpness); sv = sa[sharpness - SHARPNESS_MIN]; for (i=0; i < 2; i++) { @@ -1564,11 +1573,11 @@ static void ibmcam_set_sharpness(struct uvd *uvd) */ static void ibmcam_set_brightness(struct uvd *uvd) { - static const char proc[] = "ibmcam_set_brightness"; static const unsigned short n = 1; if (debug > 0) - info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness); + dev_info(&uvd->dev->dev, "%s: Set brightness to %hu.\n", + __func__, uvd->vpic.brightness); switch (IBMCAM_T(uvd)->camera_model) { case IBMCAM_MODEL_1: @@ -2115,7 +2124,8 @@ static void ibmcam_model2_setup_after_video_if(struct uvd *uvd) break; } if (uvd->debug > 0) - info("Framerate (hardware): %hd.", hw_fps); + dev_info(&uvd->dev->dev, "Framerate (hardware): %hd.\n", + hw_fps); RESTRICT_TO_RANGE(hw_fps, 0, 31); ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps); } @@ -3487,7 +3497,7 @@ static void ibmcam_model3_setup_after_video_if(struct uvd *uvd) /* 01.01.08 - Added for RCA video in support -LO */ if(init_model3_input) { if (debug > 0) - info("Setting input to RCA."); + dev_info(&uvd->dev->dev, "Setting input to RCA.\n"); for (i=0; i < ARRAY_SIZE(initData); i++) { ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index); } @@ -3685,7 +3695,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * unsigned char video_ep = 0; if (debug >= 1) - info("ibmcam_probe(%p,%u.)", intf, ifnum); + dev_info(&uvd->dev->dev, "ibmcam_probe(%p,%u.)\n", intf, ifnum); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) @@ -3736,14 +3746,16 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */ break; } - info("%s USB camera found (model %d, rev. 0x%04x)", - brand, model, le16_to_cpu(dev->descriptor.bcdDevice)); + dev_info(&uvd->dev->dev, + "%s USB camera found (model %d, rev. 0x%04x)\n", + brand, model, le16_to_cpu(dev->descriptor.bcdDevice)); } while (0); /* Validate found interface: must have one ISO endpoint */ nas = intf->num_altsetting; if (debug > 0) - info("Number of alternate settings=%d.", nas); + dev_info(&uvd->dev->dev, "Number of alternate settings=%d.\n", + nas); if (nas < 2) { err("Too few alternate settings for this camera!"); return -ENODEV; @@ -3787,7 +3799,9 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * actInterface = i; maxPS = le16_to_cpu(endpoint->wMaxPacketSize); if (debug > 0) - info("Active setting=%d. maxPS=%d.", i, maxPS); + dev_info(&uvd->dev->dev, + "Active setting=%d. " + "maxPS=%d.\n", i, maxPS); } else err("More than one active alt. setting! Ignoring #%d.", i); } @@ -3826,7 +3840,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * RESTRICT_TO_RANGE(framerate, 0, 5); break; default: - info("IBM camera: using 320x240"); + dev_info(&uvd->dev->dev, "IBM camera: using 320x240\n"); size = SIZE_320x240; /* No break here */ case SIZE_320x240: @@ -3855,7 +3869,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * canvasY = 120; break; default: - info("IBM NetCamera: using 176x144"); + dev_info(&uvd->dev->dev, "IBM NetCamera: using 176x144\n"); size = SIZE_176x144; /* No break here */ case SIZE_176x144: diff --git a/linux/drivers/media/video/usbvideo/konicawc.c b/linux/drivers/media/video/usbvideo/konicawc.c index 25f9b4286..5c11ea64c 100644 --- a/linux/drivers/media/video/usbvideo/konicawc.c +++ b/linux/drivers/media/video/usbvideo/konicawc.c @@ -346,7 +346,8 @@ static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct ur } if((sts > 0x01) && (sts < 0x80)) { - info("unknown status %2.2x", sts); + dev_info(&uvd->dev->dev, "unknown status %2.2x\n", + sts); bad++; continue; } @@ -581,8 +582,12 @@ static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame) fdrops = (0x80 + curframe - cam->lastframe) & 0x7F; fdrops--; if(fdrops) { - info("Dropped %d frames (%d -> %d)", fdrops, - cam->lastframe, curframe); + dev_info(&uvd->dev->dev, + "Dropped %d frames " + "(%d -> %d)\n", + fdrops, + cam->lastframe, + curframe); } } cam->lastframe = curframe; @@ -797,7 +802,8 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; - info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice)); + dev_info(&intf->dev, "Konica Webcam (rev. 0x%04x)\n", + le16_to_cpu(dev->descriptor.bcdDevice)); RESTRICT_TO_RANGE(speed, 0, MAX_SPEED); /* Validate found interface: must have one ISO endpoint */ @@ -938,7 +944,8 @@ static struct usb_device_id id_table[] = { static int __init konicawc_init(void) { struct usbvideo_cb cbTbl; - info(DRIVER_DESC " " DRIVER_VERSION); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); memset(&cbTbl, 0, sizeof(cbTbl)); cbTbl.probe = konicawc_probe; cbTbl.setupOnOpen = konicawc_setup_on_open; diff --git a/linux/drivers/media/video/usbvideo/quickcam_messenger.c b/linux/drivers/media/video/usbvideo/quickcam_messenger.c index f079e8d66..2f7274aba 100644 --- a/linux/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/linux/drivers/media/video/usbvideo/quickcam_messenger.c @@ -1097,7 +1097,8 @@ static struct usbvideo_cb qcm_driver = { static int __init qcm_init(void) { - info(DRIVER_DESC " " DRIVER_VERSION); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); return usbvideo_register( &cams, diff --git a/linux/drivers/media/video/usbvideo/ultracam.c b/linux/drivers/media/video/usbvideo/ultracam.c index bd89e6862..d29e6a81b 100644 --- a/linux/drivers/media/video/usbvideo/ultracam.c +++ b/linux/drivers/media/video/usbvideo/ultracam.c @@ -156,10 +156,11 @@ static int ultracam_veio( sizeof(cp), 1000); #if 1 /* keep */ - info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " - "(req=$%02x val=$%04x ind=$%04x)", - cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], - req, value, index); + dev_info(&uvd->dev->dev, + "USB => %02x%02x%02x%02x%02x%02x%02x%02x " + "(req=$%02x val=$%04x ind=$%04x)\n", + cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], + req, value, index); #endif } else { i = usb_control_msg( @@ -517,19 +518,20 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id unsigned char video_ep = 0; if (debug >= 1) - info("ultracam_probe(%p)", intf); + dev_info(&intf->dev, "ultracam_probe\n"); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; - info("IBM Ultra camera found (rev. 0x%04x)", - le16_to_cpu(dev->descriptor.bcdDevice)); + dev_info(&intf->dev, "IBM Ultra camera found (rev. 0x%04x)\n", + le16_to_cpu(dev->descriptor.bcdDevice)); /* Validate found interface: must have one ISO endpoint */ nas = intf->num_altsetting; if (debug > 0) - info("Number of alternate settings=%d.", nas); + dev_info(&intf->dev, "Number of alternate settings=%d.\n", + nas); if (nas < 8) { err("Too few alternate settings for this camera!"); return -ENODEV; @@ -576,7 +578,9 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id actInterface = i; maxPS = le16_to_cpu(endpoint->wMaxPacketSize); if (debug > 0) - info("Active setting=%d. maxPS=%d.", i, maxPS); + dev_info(&intf->dev, + "Active setting=%d. " + "maxPS=%d.\n", i, maxPS); } else { /* Got another active alt. setting */ if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) { @@ -584,8 +588,11 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id actInterface = i; maxPS = le16_to_cpu(endpoint->wMaxPacketSize); if (debug > 0) { - info("Even better ctive setting=%d. maxPS=%d.", - i, maxPS); + dev_info(&intf->dev, + "Even better ctive " + "setting=%d. " + "maxPS=%d.\n", + i, maxPS); } } } diff --git a/linux/drivers/media/video/usbvideo/usbvideo.c b/linux/drivers/media/video/usbvideo/usbvideo.c index 2e29d95b6..c6d1e7dca 100644 --- a/linux/drivers/media/video/usbvideo/usbvideo.c +++ b/linux/drivers/media/video/usbvideo/usbvideo.c @@ -468,8 +468,9 @@ static void usbvideo_ReportStatistics(const struct uvd *uvd) percent = (100 * goodPackets) / allPackets; else percent = goodPackets / (allPackets / 100); - info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%", - allPackets, badPackets, percent); + dev_info(&uvd->dev->dev, + "Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%\n", + allPackets, badPackets, percent); if (uvd->iso_packet_len > 0) { unsigned long allBytes, xferBytes; char multiplier = ' '; @@ -497,8 +498,9 @@ static void usbvideo_ReportStatistics(const struct uvd *uvd) } } } - info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%", - xferBytes, multiplier, percent); + dev_info(&uvd->dev->dev, + "Transfer Statistics: Transferred=%lu%cB Usage=%lu%%\n", + xferBytes, multiplier, percent); } } } @@ -545,7 +547,7 @@ void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode) { /* For debugging purposes only */ char tmp[20]; usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request); - info("testpattern: frame=%s", tmp); + dev_info(&uvd->dev->dev, "testpattern: frame=%s\n", tmp); } #endif /* Form every scan line */ @@ -854,7 +856,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf) usbvideo_ClientIncModCount(uvd); if (uvd->debug > 0) - info("%s(%p.)", __func__, intf); + dev_info(&intf->dev, "%s(%p.)\n", __func__, intf); mutex_lock(&uvd->lock); uvd->remove_pending = 1; /* Now all ISO data will be ignored */ @@ -870,14 +872,15 @@ static void usbvideo_Disconnect(struct usb_interface *intf) video_unregister_device(&uvd->vdev); if (uvd->debug > 0) - info("%s: Video unregistered.", __func__); + dev_info(&intf->dev, "%s: Video unregistered.\n", __func__); if (uvd->user) - info("%s: In use, disconnect pending.", __func__); + dev_info(&intf->dev, "%s: In use, disconnect pending.\n", + __func__); else usbvideo_CameraRelease(uvd); mutex_unlock(&uvd->lock); - info("USB camera disconnected."); + dev_info(&intf->dev, "USB camera disconnected.\n"); usbvideo_ClientDecModCount(uvd); } @@ -1015,14 +1018,17 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) return -EINVAL; } if (uvd->video_endp == 0) { - info("%s: No video endpoint specified; data pump disabled.", __func__); + dev_info(&uvd->dev->dev, + "%s: No video endpoint specified; data pump disabled.\n", + __func__); } if (uvd->paletteBits == 0) { err("%s: No palettes specified!", __func__); return -EINVAL; } if (uvd->defaultPalette == 0) { - info("%s: No default palette!", __func__); + dev_info(&uvd->dev->dev, "%s: No default palette!\n", + __func__); } uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) * @@ -1031,8 +1037,10 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas); if (uvd->debug > 0) { - info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx", - __func__, uvd->iface, uvd->video_endp, uvd->paletteBits); + dev_info(&uvd->dev->dev, + "%s: iface=%d. endpoint=$%02x paletteBits=$%08lx\n", + __func__, uvd->iface, uvd->video_endp, + uvd->paletteBits); } if (uvd->dev == NULL) { err("%s: uvd->dev == NULL", __func__); @@ -1045,12 +1053,13 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) return -EPIPE; } if (uvd->debug > 1) { - info("%s: video_register_device() successful", __func__); + dev_info(&uvd->dev->dev, + "%s: video_register_device() successful\n", __func__); } - info("%s on /dev/video%d: canvas=%s videosize=%s", - (uvd->handle != NULL) ? uvd->handle->drvName : "???", - uvd->vdev.minor, tmp2, tmp1); + dev_info(&uvd->dev->dev, "%s on /dev/video%d: canvas=%s videosize=%s\n", + (uvd->handle != NULL) ? uvd->handle->drvName : "???", + uvd->vdev.minor, tmp2, tmp1); usb_get_dev(uvd->dev); return 0; @@ -1112,7 +1121,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) int i, errCode = 0; if (uvd->debug > 1) - info("%s($%p)", __func__, dev); + dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev); if (0 < usbvideo_ClientIncModCount(uvd)) return -ENODEV; @@ -1179,19 +1188,25 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) if (errCode == 0) { if (VALID_CALLBACK(uvd, setupOnOpen)) { if (uvd->debug > 1) - info("%s: setupOnOpen callback", __func__); + dev_info(&uvd->dev->dev, + "%s: setupOnOpen callback\n", + __func__); errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); if (errCode < 0) { err("%s: setupOnOpen callback failed (%d.).", __func__, errCode); } else if (uvd->debug > 1) { - info("%s: setupOnOpen callback successful", __func__); + dev_info(&uvd->dev->dev, + "%s: setupOnOpen callback successful\n", + __func__); } } if (errCode == 0) { uvd->settingsAdjusted = 0; if (uvd->debug > 1) - info("%s: Open succeeded.", __func__); + dev_info(&uvd->dev->dev, + "%s: Open succeeded.\n", + __func__); uvd->user++; file->private_data = uvd; } @@ -1201,7 +1216,8 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) if (errCode != 0) usbvideo_ClientDecModCount(uvd); if (uvd->debug > 0) - info("%s: Returning %d.", __func__, errCode); + dev_info(&uvd->dev->dev, "%s: Returning %d.\n", __func__, + errCode); return errCode; } @@ -1224,7 +1240,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file) int i; if (uvd->debug > 1) - info("%s($%p)", __func__, dev); + dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev); mutex_lock(&uvd->lock); GET_CALLBACK(uvd, stopDataPump)(uvd); @@ -1244,14 +1260,15 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file) uvd->user--; if (uvd->remove_pending) { if (uvd->debug > 0) - info("usbvideo_v4l_close: Final disconnect."); + dev_info(&uvd->dev->dev, "%s: Final disconnect.\n", + __func__); usbvideo_CameraRelease(uvd); } mutex_unlock(&uvd->lock); usbvideo_ClientDecModCount(uvd); if (uvd->debug > 1) - info("%s: Completed.", __func__); + dev_info(&uvd->dev->dev, "%s: Completed.\n", __func__); file->private_data = NULL; return 0; } @@ -1365,8 +1382,9 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, struct video_mmap *vm = arg; if (uvd->debug >= 1) { - info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.", - vm->frame, vm->width, vm->height, vm->format); + dev_info(&uvd->dev->dev, + "VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.\n", + vm->frame, vm->width, vm->height, vm->format); } /* * Check if the requested size is supported. If the requestor @@ -1384,18 +1402,24 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, if ((vm->width > VIDEOSIZE_X(uvd->canvas)) || (vm->height > VIDEOSIZE_Y(uvd->canvas))) { if (uvd->debug > 0) { - info("VIDIOCMCAPTURE: Size=%dx%d too large; " - "allowed only up to %ldx%ld", vm->width, vm->height, - VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas)); + dev_info(&uvd->dev->dev, + "VIDIOCMCAPTURE: Size=%dx%d " + "too large; allowed only up " + "to %ldx%ld\n", vm->width, + vm->height, + VIDEOSIZE_X(uvd->canvas), + VIDEOSIZE_Y(uvd->canvas)); } return -EINVAL; } /* Check if the palette is supported */ if (((1L << vm->format) & uvd->paletteBits) == 0) { if (uvd->debug > 0) { - info("VIDIOCMCAPTURE: format=%d. not supported" - " (paletteBits=$%08lx)", - vm->format, uvd->paletteBits); + dev_info(&uvd->dev->dev, + "VIDIOCMCAPTURE: format=%d. " + "not supported " + "(paletteBits=$%08lx)\n", + vm->format, uvd->paletteBits); } return -EINVAL; } @@ -1423,7 +1447,9 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (uvd->debug >= 1) - info("VIDIOCSYNC: syncing to frame %d.", *frameNum); + dev_info(&uvd->dev->dev, + "VIDIOCSYNC: syncing to frame %d.\n", + *frameNum); if (uvd->flags & FLAGS_NO_DECODING) ret = usbvideo_GetFrame(uvd, *frameNum); else if (VALID_CALLBACK(uvd, getFrame)) { @@ -1505,7 +1531,9 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, return -EFAULT; if (uvd->debug >= 1) - info("%s: %Zd. bytes, noblock=%d.", __func__, count, noblock); + dev_info(&uvd->dev->dev, + "%s: %Zd. bytes, noblock=%d.\n", + __func__, count, noblock); mutex_lock(&uvd->lock); @@ -1690,18 +1718,21 @@ static void usbvideo_IsocIrq(struct urb *urb) return; #if 0 /* keep */ if (urb->actual_length > 0) { - info("urb=$%p status=%d. errcount=%d. length=%d.", - urb, urb->status, urb->error_count, urb->actual_length); + dev_info(&uvd->dev->dev, + "urb=$%p status=%d. errcount=%d. length=%d.\n", + urb, urb->status, urb->error_count, + urb->actual_length); } else { static int c = 0; if (c++ % 100 == 0) - info("No Isoc data"); + dev_info(&uvd->dev->dev, "No Isoc data\n"); } #endif if (!uvd->streaming) { if (uvd->debug >= 1) - info("Not streaming, but interrupt!"); + dev_info(&uvd->dev->dev, + "Not streaming, but interrupt!\n"); return; } @@ -1746,7 +1777,7 @@ static int usbvideo_StartDataPump(struct uvd *uvd) int i, errFlag; if (uvd->debug > 1) - info("%s($%p)", __func__, uvd); + dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd); if (!CAMERA_IS_OPERATIONAL(uvd)) { err("%s: Camera is not operational", __func__); @@ -1794,7 +1825,9 @@ static int usbvideo_StartDataPump(struct uvd *uvd) uvd->streaming = 1; if (uvd->debug > 1) - info("%s: streaming=1 video_endp=$%02x", __func__, uvd->video_endp); + dev_info(&uvd->dev->dev, + "%s: streaming=1 video_endp=$%02x\n", __func__, + uvd->video_endp); return 0; } @@ -1816,14 +1849,14 @@ static void usbvideo_StopDataPump(struct uvd *uvd) return; if (uvd->debug > 1) - info("%s($%p)", __func__, uvd); + dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd); /* Unschedule all of the iso td's */ for (i=0; i < USBVIDEO_NUMSBUF; i++) { usb_kill_urb(uvd->sbuf[i].urb); } if (uvd->debug > 1) - info("%s: streaming=0", __func__); + dev_info(&uvd->dev->dev, "%s: streaming=0\n", __func__); uvd->streaming = 0; if (!uvd->remove_pending) { @@ -1855,7 +1888,8 @@ static int usbvideo_NewFrame(struct uvd *uvd, int framenum) int n; if (uvd->debug > 1) - info("usbvideo_NewFrame($%p,%d.)", uvd, framenum); + dev_info(&uvd->dev->dev, "usbvideo_NewFrame($%p,%d.)\n", uvd, + framenum); /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ @@ -1960,12 +1994,14 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) struct usbvideo_frame *frame = &uvd->frame[frameNum]; if (uvd->debug >= 2) - info("%s($%p,%d.)", __func__, uvd, frameNum); + dev_info(&uvd->dev->dev, "%s($%p,%d.)\n", __func__, uvd, + frameNum); switch (frame->frameState) { case FrameState_Unused: if (uvd->debug >= 2) - info("%s: FrameState_Unused", __func__); + dev_info(&uvd->dev->dev, "%s: FrameState_Unused\n", + __func__); return -EINVAL; case FrameState_Ready: case FrameState_Grabbing: @@ -1975,7 +2011,9 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) redo: if (!CAMERA_IS_OPERATIONAL(uvd)) { if (uvd->debug >= 2) - info("%s: Camera is not operational (1)", __func__); + dev_info(&uvd->dev->dev, + "%s: Camera is not operational (1)\n", + __func__); return -EIO; } ntries = 0; @@ -1984,24 +2022,33 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) signalPending = signal_pending(current); if (!CAMERA_IS_OPERATIONAL(uvd)) { if (uvd->debug >= 2) - info("%s: Camera is not operational (2)", __func__); + dev_info(&uvd->dev->dev, + "%s: Camera is not " + "operational (2)\n", __func__); return -EIO; } assert(uvd->fbuf != NULL); if (signalPending) { if (uvd->debug >= 2) - info("%s: Signal=$%08x", __func__, signalPending); + dev_info(&uvd->dev->dev, + "%s: Signal=$%08x\n", __func__, + signalPending); if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) { usbvideo_TestPattern(uvd, 1, 0); uvd->curframe = -1; uvd->stats.frame_num++; if (uvd->debug >= 2) - info("%s: Forced test pattern screen", __func__); + dev_info(&uvd->dev->dev, + "%s: Forced test " + "pattern screen\n", + __func__); return 0; } else { /* Standard answer: Interrupted! */ if (uvd->debug >= 2) - info("%s: Interrupted!", __func__); + dev_info(&uvd->dev->dev, + "%s: Interrupted!\n", + __func__); return -EINTR; } } else { @@ -2015,8 +2062,10 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) } } while (frame->frameState == FrameState_Grabbing); if (uvd->debug >= 2) { - info("%s: Grabbing done; state=%d. (%lu. bytes)", - __func__, frame->frameState, frame->seqRead_Length); + dev_info(&uvd->dev->dev, + "%s: Grabbing done; state=%d. (%lu. bytes)\n", + __func__, frame->frameState, + frame->seqRead_Length); } if (frame->frameState == FrameState_Error) { int ret = usbvideo_NewFrame(uvd, frameNum); @@ -2053,7 +2102,9 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) } frame->frameState = FrameState_Done_Hold; if (uvd->debug >= 2) - info("%s: Entered FrameState_Done_Hold state.", __func__); + dev_info(&uvd->dev->dev, + "%s: Entered FrameState_Done_Hold state.\n", + __func__); return 0; case FrameState_Done_Hold: @@ -2064,7 +2115,9 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) * it will be released back into the wild to roam freely. */ if (uvd->debug >= 2) - info("%s: FrameState_Done_Hold state.", __func__); + dev_info(&uvd->dev->dev, + "%s: FrameState_Done_Hold state.\n", + __func__); return 0; } diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c index 8c2b53513..d66cce1a5 100644 --- a/linux/drivers/media/video/usbvision/usbvision-core.c +++ b/linux/drivers/media/video/usbvision/usbvision-core.c @@ -84,7 +84,8 @@ MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]"); #ifdef USBVISION_DEBUG #define PDEBUG(level, fmt, args...) { \ if (core_debug & (level)) \ - info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \ + printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ + __func__, __LINE__ , ## args); \ } #else #define PDEBUG(level, fmt, args...) do {} while(0) diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c index 9d2f6b985..d98eb913e 100644 --- a/linux/drivers/media/video/usbvision/usbvision-i2c.c +++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c @@ -48,7 +48,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); #define PDEBUG(level, fmt, args...) { \ if (i2c_debug & (level)) \ - info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \ + printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ + __func__, __LINE__ , ## args); \ } static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c index 782ee6436..e10b256ae 100644 --- a/linux/drivers/media/video/usbvision/usbvision-video.c +++ b/linux/drivers/media/video/usbvision/usbvision-video.c @@ -98,7 +98,8 @@ USBVISION_DRIVER_VERSION_PATCHLEVEL) #ifdef USBVISION_DEBUG #define PDEBUG(level, fmt, args...) { \ if (video_debug & (level)) \ - info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \ + printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ + __func__, __LINE__ , ## args); \ } #else #define PDEBUG(level, fmt, args...) do {} while(0) diff --git a/linux/drivers/media/video/zoran/Kconfig b/linux/drivers/media/video/zoran/Kconfig new file mode 100644 index 000000000..4ea5fa71d --- /dev/null +++ b/linux/drivers/media/video/zoran/Kconfig @@ -0,0 +1,73 @@ +config VIDEO_ZORAN + tristate "Zoran ZR36057/36067 Video For Linux" + depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS + help + Say Y for support for MJPEG capture cards based on the Zoran + 36057/36067 PCI controller chipset. This includes the Iomega + Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is + a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For + more information, check <file:Documentation/video4linux/Zoran>. + + To compile this driver as a module, choose M here: the + module will be called zr36067. + +config VIDEO_ZORAN_DC30 + tristate "Pinnacle/Miro DC30(+) support" + depends on VIDEO_ZORAN + select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO + help + Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback + card. This also supports really old DC10 cards based on the + zr36050 MJPEG codec and zr36016 VFE. + +config VIDEO_ZORAN_ZR36060 + tristate "Zoran ZR36060" + depends on VIDEO_ZORAN + help + Say Y to support Zoran boards based on 36060 chips. + This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 + and 33 R10 and AverMedia 6 boards. + +config VIDEO_ZORAN_BUZ + tristate "Iomega Buz support" + depends on VIDEO_ZORAN_ZR36060 + select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO + help + Support for the Iomega Buz MJPEG capture/playback card. + +config VIDEO_ZORAN_DC10 + tristate "Pinnacle/Miro DC10(+) support" + depends on VIDEO_ZORAN_ZR36060 + select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO + help + Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback + card. + +config VIDEO_ZORAN_LML33 + tristate "Linux Media Labs LML33 support" + depends on VIDEO_ZORAN_ZR36060 + select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO + help + Support for the Linux Media Labs LML33 MJPEG capture/playback + card. + +config VIDEO_ZORAN_LML33R10 + tristate "Linux Media Labs LML33R10 support" + depends on VIDEO_ZORAN_ZR36060 + select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO + help + support for the Linux Media Labs LML33R10 MJPEG capture/playback + card. + +config VIDEO_ZORAN_AVS6EYES + tristate "AverMedia 6 Eyes support (EXPERIMENTAL)" + depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1 + select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO + help + Support for the AverMedia 6 Eyes video surveillance card. diff --git a/linux/drivers/media/video/zoran/Makefile b/linux/drivers/media/video/zoran/Makefile new file mode 100644 index 000000000..44cc13352 --- /dev/null +++ b/linux/drivers/media/video/zoran/Makefile @@ -0,0 +1,6 @@ +zr36067-objs := zoran_procfs.o zoran_device.o \ + zoran_driver.o zoran_card.o + +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o +obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o +obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o diff --git a/linux/drivers/media/video/videocodec.c b/linux/drivers/media/video/zoran/videocodec.c index cf24956f3..cf24956f3 100644 --- a/linux/drivers/media/video/videocodec.c +++ b/linux/drivers/media/video/zoran/videocodec.c diff --git a/linux/drivers/media/video/videocodec.h b/linux/drivers/media/video/zoran/videocodec.h index 1b40df14f..1b40df14f 100644 --- a/linux/drivers/media/video/videocodec.h +++ b/linux/drivers/media/video/zoran/videocodec.h diff --git a/linux/drivers/media/video/zoran.h b/linux/drivers/media/video/zoran/zoran.h index 46b7ad477..46b7ad477 100644 --- a/linux/drivers/media/video/zoran.h +++ b/linux/drivers/media/video/zoran/zoran.h diff --git a/linux/drivers/media/video/zoran_card.c b/linux/drivers/media/video/zoran/zoran_card.c index 081b72a45..081b72a45 100644 --- a/linux/drivers/media/video/zoran_card.c +++ b/linux/drivers/media/video/zoran/zoran_card.c diff --git a/linux/drivers/media/video/zoran_card.h b/linux/drivers/media/video/zoran/zoran_card.h index e4dc9d29b..e4dc9d29b 100644 --- a/linux/drivers/media/video/zoran_card.h +++ b/linux/drivers/media/video/zoran/zoran_card.h diff --git a/linux/drivers/media/video/zoran_device.c b/linux/drivers/media/video/zoran/zoran_device.c index 87f894fa2..87f894fa2 100644 --- a/linux/drivers/media/video/zoran_device.c +++ b/linux/drivers/media/video/zoran/zoran_device.c diff --git a/linux/drivers/media/video/zoran_device.h b/linux/drivers/media/video/zoran/zoran_device.h index d4e0b9b5a..d4e0b9b5a 100644 --- a/linux/drivers/media/video/zoran_device.h +++ b/linux/drivers/media/video/zoran/zoran_device.h diff --git a/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran/zoran_driver.c index 9d57a630c..9d57a630c 100644 --- a/linux/drivers/media/video/zoran_driver.c +++ b/linux/drivers/media/video/zoran/zoran_driver.c diff --git a/linux/drivers/media/video/zoran_procfs.c b/linux/drivers/media/video/zoran/zoran_procfs.c index 961950a21..961950a21 100644 --- a/linux/drivers/media/video/zoran_procfs.c +++ b/linux/drivers/media/video/zoran/zoran_procfs.c diff --git a/linux/drivers/media/video/zoran_procfs.h b/linux/drivers/media/video/zoran/zoran_procfs.h index f2d5b1ba4..f2d5b1ba4 100644 --- a/linux/drivers/media/video/zoran_procfs.h +++ b/linux/drivers/media/video/zoran/zoran_procfs.h diff --git a/linux/drivers/media/video/zr36016.c b/linux/drivers/media/video/zoran/zr36016.c index 693a648e9..693a648e9 100644 --- a/linux/drivers/media/video/zr36016.c +++ b/linux/drivers/media/video/zoran/zr36016.c diff --git a/linux/drivers/media/video/zr36016.h b/linux/drivers/media/video/zoran/zr36016.h index 8c79229f6..8c79229f6 100644 --- a/linux/drivers/media/video/zr36016.h +++ b/linux/drivers/media/video/zoran/zr36016.h diff --git a/linux/drivers/media/video/zr36050.c b/linux/drivers/media/video/zoran/zr36050.c index cf8b271a1..cf8b271a1 100644 --- a/linux/drivers/media/video/zr36050.c +++ b/linux/drivers/media/video/zoran/zr36050.c diff --git a/linux/drivers/media/video/zr36050.h b/linux/drivers/media/video/zoran/zr36050.h index 9f52f0cdd..9f52f0cdd 100644 --- a/linux/drivers/media/video/zr36050.h +++ b/linux/drivers/media/video/zoran/zr36050.h diff --git a/linux/drivers/media/video/zr36057.h b/linux/drivers/media/video/zoran/zr36057.h index 54c9362aa..54c9362aa 100644 --- a/linux/drivers/media/video/zr36057.h +++ b/linux/drivers/media/video/zoran/zr36057.h diff --git a/linux/drivers/media/video/zr36060.c b/linux/drivers/media/video/zoran/zr36060.c index 8e74054d5..8e74054d5 100644 --- a/linux/drivers/media/video/zr36060.c +++ b/linux/drivers/media/video/zoran/zr36060.c diff --git a/linux/drivers/media/video/zr36060.h b/linux/drivers/media/video/zoran/zr36060.h index 914ffa4ad..914ffa4ad 100644 --- a/linux/drivers/media/video/zr36060.h +++ b/linux/drivers/media/video/zoran/zr36060.h diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c index a2a632534..b0da282a5 100644 --- a/linux/drivers/media/video/zr364xx.c +++ b/linux/drivers/media/video/zr364xx.c @@ -53,7 +53,7 @@ /* Debug macro */ -#define DBG(x...) if (debug) info(x) +#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x) /* Init methods, need to find nicer names for these @@ -129,7 +129,7 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value, unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); if (!transfer_buffer) { - info("kmalloc(%d) failed", size); + dev_err(&udev->dev, "kmalloc(%d) failed\n", size); return -ENOMEM; } @@ -145,7 +145,8 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value, kfree(transfer_buffer); if (status < 0) - info("Failed sending control message, error %d.", status); + dev_err(&udev->dev, + "Failed sending control message, error %d.\n", status); return status; } @@ -305,11 +306,11 @@ static int read_frame(struct zr364xx_camera *cam, int framenum) DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]); DBG("bulk : n=%d size=%d", n, actual_length); if (n < 0) { - info("error reading bulk msg"); + dev_err(&cam->udev->dev, "error reading bulk msg\n"); return 0; } if (actual_length < 0 || actual_length > BUFFER_SIZE) { - info("wrong number of bytes"); + dev_err(&cam->udev->dev, "wrong number of bytes\n"); return 0; } @@ -653,7 +654,7 @@ static int zr364xx_open(struct inode *inode, struct file *file) if (!cam->framebuf) { cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES); if (!cam->framebuf) { - info("vmalloc_32 failed!"); + dev_err(&cam->udev->dev, "vmalloc_32 failed!\n"); err = -ENOMEM; goto out; } @@ -665,7 +666,8 @@ static int zr364xx_open(struct inode *inode, struct file *file) 0, init[cam->method][i].bytes, init[cam->method][i].size); if (err < 0) { - info("error during open sequence: %d", i); + dev_err(&cam->udev->dev, + "error during open sequence: %d\n", i); goto out; } } @@ -713,7 +715,7 @@ static int zr364xx_release(struct inode *inode, struct file *file) 0, init[i][cam->method].bytes, init[cam->method][i].size); if (err < 0) { - info("error during release sequence"); + dev_err(&udev->dev, "error during release sequence\n"); goto out; } } @@ -809,13 +811,14 @@ static int zr364xx_probe(struct usb_interface *intf, DBG("probing..."); - info(DRIVER_DESC " compatible webcam plugged"); - info("model %04x:%04x detected", udev->descriptor.idVendor, - udev->descriptor.idProduct); + dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n"); + dev_info(&intf->dev, "model %04x:%04x detected\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL); if (cam == NULL) { - info("cam: out of memory !"); + dev_err(&udev->dev, "cam: out of memory !\n"); return -ENOMEM; } /* save the init method used by this camera */ @@ -823,7 +826,7 @@ static int zr364xx_probe(struct usb_interface *intf, cam->vdev = video_device_alloc(); if (cam->vdev == NULL) { - info("cam->vdev: out of memory !"); + dev_err(&udev->dev, "cam->vdev: out of memory !\n"); kfree(cam); return -ENOMEM; } @@ -835,7 +838,7 @@ static int zr364xx_probe(struct usb_interface *intf, cam->udev = udev; if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) { - info("cam->buffer: out of memory !"); + dev_info(&udev->dev, "cam->buffer: out of memory !\n"); video_device_release(cam->vdev); kfree(cam); return -ENODEV; @@ -843,17 +846,17 @@ static int zr364xx_probe(struct usb_interface *intf, switch (mode) { case 1: - info("160x120 mode selected"); + dev_info(&udev->dev, "160x120 mode selected\n"); cam->width = 160; cam->height = 120; break; case 2: - info("640x480 mode selected"); + dev_info(&udev->dev, "640x480 mode selected\n"); cam->width = 640; cam->height = 480; break; default: - info("320x240 mode selected"); + dev_info(&udev->dev, "320x240 mode selected\n"); cam->width = 320; cam->height = 240; break; @@ -873,7 +876,7 @@ static int zr364xx_probe(struct usb_interface *intf, err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1); if (err) { - info("video_register_device failed"); + dev_err(&udev->dev, "video_register_device failed\n"); video_device_release(cam->vdev); kfree(cam->buffer); kfree(cam); @@ -882,7 +885,8 @@ static int zr364xx_probe(struct usb_interface *intf, usb_set_intfdata(intf, cam); - info(DRIVER_DESC " controlling video device %d", cam->vdev->minor); + dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n", + cam->vdev->minor); return 0; } @@ -892,7 +896,7 @@ static void zr364xx_disconnect(struct usb_interface *intf) struct zr364xx_camera *cam = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); dev_set_drvdata(&intf->dev, NULL); - info(DRIVER_DESC " webcam unplugged"); + dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n"); if (cam->vdev) video_unregister_device(cam->vdev); cam->vdev = NULL; @@ -921,16 +925,16 @@ static int __init zr364xx_init(void) int retval; retval = usb_register(&zr364xx_driver); if (retval) - info("usb_register failed!"); + printk(KERN_ERR KBUILD_MODNAME ": usb_register failed!\n"); else - info(DRIVER_DESC " module loaded"); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); return retval; } static void __exit zr364xx_exit(void) { - info(DRIVER_DESC " module unloaded"); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC " module unloaded\n"); usb_deregister(&zr364xx_driver); } |