diff options
Diffstat (limited to 'linux/drivers/media')
34 files changed, 1357 insertions, 302 deletions
diff --git a/linux/drivers/media/dvb/frontends/isl6421.c b/linux/drivers/media/dvb/frontends/isl6421.c index ef319369e..c967148a5 100644 --- a/linux/drivers/media/dvb/frontends/isl6421.c +++ b/linux/drivers/media/dvb/frontends/isl6421.c @@ -122,6 +122,7 @@ struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter /* detect if it is present or not */ if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) { kfree(isl6421); + fe->sec_priv = NULL; return NULL; } diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c index b0e6c3e9c..d26dcf3d4 100644 --- a/linux/drivers/media/video/bt8xx/bttv-cards.c +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c @@ -3015,20 +3015,20 @@ void __devinit bttv_idcard(struct bttv *btv) if (UNSET != audiomux[0]) { gpiobits = 0; - for (i = 0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; gpiobits |= audiomux[i]; } } else { gpiobits = audioall; - for (i = 0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { bttv_tvcards[btv->c.type].gpiomux[i] = audioall; } } bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); - for (i = 0; i < 5; i++) { + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); } printk("\n"); @@ -3692,7 +3692,7 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen) for (n = 0; n < microlen; n++) { bits = micro[n]; - for ( i = 0 ; i < 8 ; i++ ) { + for (i = 0 ; i < 8 ; i++) { gpio_bits(BTTV_ALT_DCLK,0); if (bits & 0x01) gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); @@ -3749,7 +3749,7 @@ static void __devinit osprey_eeprom(struct bttv *btv) /* this might be an antique... check for MMAC label in eeprom */ if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { unsigned char checksum = 0; - for (i =0; i<21; i++) + for (i = 0; i < 21; i++) checksum += ee[i]; if (checksum != ee[21]) return; @@ -3761,12 +3761,13 @@ static void __devinit osprey_eeprom(struct bttv *btv) unsigned short type; int offset = 4*16; - for(; offset < 8*16; offset += 16) { + for (; offset < 8*16; offset += 16) { unsigned short checksum = 0; /* verify the checksum */ - for(i = 0; i<14; i++) checksum += ee[i+offset]; - checksum = ~checksum; /* no idea why */ - if ((((checksum>>8)&0x0FF) == ee[offset+14]) && + for (i = 0; i < 14; i++) + checksum += ee[i+offset]; + checksum = ~checksum; /* no idea why */ + if ((((checksum>>8)&0x0FF) == ee[offset+14]) && ((checksum & 0x0FF) == ee[offset+15])) { break; } @@ -3779,7 +3780,6 @@ static void __devinit osprey_eeprom(struct bttv *btv) type = (ee[offset+4]<<8) | (ee[offset+5]); switch(type) { - /* 848 based */ case 0x0004: btv->c.type = BTTV_BOARD_OSPREY1x0_848; @@ -4245,8 +4245,7 @@ static int tea5757_read(struct bttv *btv) } dprintk("bttv%d: tea5757:",btv->c.nr); - for(i = 0; i < 24; i++) - { + for (i = 0; i < 24; i++) { udelay(5); bus_high(btv,btv->mbox_clk); udelay(5); @@ -4278,8 +4277,7 @@ static int tea5757_write(struct bttv *btv, int value) dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); bus_low(btv,btv->mbox_clk); bus_high(btv,btv->mbox_we); - for(i = 0; i < 25; i++) - { + for (i = 0; i < 25; i++) { if (reg & 0x1000000) bus_high(btv,btv->mbox_data); else @@ -4871,7 +4869,7 @@ static void kodicom4400r_init(struct bttv *btv) gpio_write(1 << 9); /* reset MUX */ gpio_write(0); /* Preset camera 0 to the 4 controllers */ - for (ix=0; ix<4; ix++) { + for (ix = 0; ix < 4; ix++) { sw_status[ix] = ix; kodicom4400r_write(btv, ix, ix, 1); } diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index 25a61e379..2aad57b5a 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -177,6 +177,36 @@ static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); #endif /* ----------------------------------------------------------------------- */ +/* dvb auto-load setup */ +#if defined(CONFIG_MODULES) && defined(MODULE) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void request_module_async(void *ptr) +#else +static void request_module_async(struct work_struct *work) +#endif +{ + request_module("dvb-bt8xx"); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#define request_modules(dev) +#else +static void request_modules(struct bttv *dev) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&dev->request_module_wk, request_module_async, (void*)dev); +#else + INIT_WORK(&dev->request_module_wk, request_module_async); +#endif + schedule_work(&dev->request_module_wk); +} +#endif +#else +#define request_modules(dev) +#endif /* CONFIG_MODULES */ + + +/* ----------------------------------------------------------------------- */ /* static data */ /* special timing tables from conexant... */ @@ -4811,9 +4841,11 @@ static int __devinit bttv_probe(struct pci_dev *dev, } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - /* add subdevices */ - if (bttv_tvcards[btv->c.type].has_dvb) + /* add subdevices and autoload dvb-bt8xx if needed */ + if (bttv_tvcards[btv->c.type].has_dvb) { bttv_sub_add_device(&btv->c, "dvb"); + request_modules(btv); + } #endif bttv_input_init(btv); diff --git a/linux/drivers/media/video/bt8xx/bttv-i2c.c b/linux/drivers/media/video/bt8xx/bttv-i2c.c index 68522754a..3f545c610 100644 --- a/linux/drivers/media/video/bt8xx/bttv-i2c.c +++ b/linux/drivers/media/video/bt8xx/bttv-i2c.c @@ -426,7 +426,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i,rc; - for (i = 0; i < 128; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { c->addr = i; rc = i2c_master_recv(c,&buf,0); if (rc < 0) diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h index a273c424b..eee6f5ae3 100644 --- a/linux/drivers/media/video/bt8xx/bttvp.h +++ b/linux/drivers/media/video/bt8xx/bttvp.h @@ -452,6 +452,9 @@ struct bttv { unsigned int users; struct bttv_fh init; + /* used to make dvb-bt8xx autoloadable */ + struct work_struct request_module_wk; + /* Default (0) and current (1) video capturing and overlay cropping parameters in bttv_tvnorm.cropcap units. Protected by bttv.lock. */ diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c index b96d45654..ea69590a1 100644 --- a/linux/drivers/media/video/cafe_ccic.c +++ b/linux/drivers/media/video/cafe_ccic.c @@ -38,7 +38,7 @@ #include "cafe_ccic-regs.h" -#define CAFE_VERSION 0x000001 +#define CAFE_VERSION 0x000002 /* @@ -712,7 +712,13 @@ static void cafe_ctlr_init(struct cafe_camera *cam) cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); + /* + * Here we must wait a bit for the controller to come around. + */ + spin_unlock_irqrestore(&cam->dev_lock, flags); mdelay(5); /* FIXME revisit this */ + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); /* @@ -780,9 +786,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam) * Control 1 is power down, set to 0 to operate. */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ - mdelay(1); /* Marvell says 1ms will do it */ +// mdelay(1); /* Marvell says 1ms will do it */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); - mdelay(1); /* Enough? */ +// mdelay(1); /* Enough? */ spin_unlock_irqrestore(&cam->dev_lock, flags); } @@ -1803,18 +1809,19 @@ static void cafe_frame_tasklet(unsigned long data) if (list_empty(&cam->sb_avail)) break; /* Leave it valid, hope for better later */ clear_bit(bufno, &cam->flags); - /* - * We could perhaps drop the spinlock during this - * big copy. Something to consider. - */ sbuf = list_entry(cam->sb_avail.next, struct cafe_sio_buffer, list); + /* + * Drop the lock during the big copy. This *should* be safe... + */ + spin_unlock_irqrestore(&cam->dev_lock, flags); memcpy(sbuf->buffer, cam->dma_bufs[bufno], cam->pix_format.sizeimage); sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; + spin_lock_irqsave(&cam->dev_lock, flags); list_move_tail(&sbuf->list, &cam->sb_full); } if (! list_empty(&cam->sb_full)) @@ -2118,6 +2125,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, cam->v4ldev = cafe_v4l_template; cam->v4ldev.debug = 0; // cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; + cam->v4ldev.dev = &pdev->dev; ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); if (ret) goto out_smbus; @@ -2187,10 +2195,48 @@ static void cafe_pci_remove(struct pci_dev *pdev) } +#ifdef CONFIG_PM +/* + * Basic power management. + */ +static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct cafe_camera *cam = cafe_find_by_pdev(pdev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + cafe_ctlr_stop_dma(cam); + cafe_ctlr_power_down(cam); + pci_disable_device(pdev); + return 0; +} + + +static int cafe_pci_resume(struct pci_dev *pdev) +{ + struct cafe_camera *cam = cafe_find_by_pdev(pdev); + int ret = 0; + + ret = pci_restore_state(pdev); + if (ret) + return ret; + pci_enable_device(pdev); + cafe_ctlr_init(cam); + cafe_ctlr_power_up(cam); + set_bit(CF_CONFIG_NEEDED, &cam->flags); + if (cam->state == S_SPECREAD) + cam->state = S_IDLE; /* Don't bother restarting */ + else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING) + ret = cafe_read_setup(cam, cam->state); + return ret; +} + +#endif /* CONFIG_PM */ static struct pci_device_id cafe_ids[] = { - { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */ { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ { 0, } @@ -2203,6 +2249,10 @@ static struct pci_driver cafe_pci_driver = { .id_table = cafe_ids, .probe = cafe_pci_probe, .remove = cafe_pci_remove, +#ifdef CONFIG_PM + .suspend = cafe_pci_suspend, + .resume = cafe_pci_resume, +#endif }; diff --git a/linux/drivers/media/video/cpia_pp.c b/linux/drivers/media/video/cpia_pp.c index 337675e96..d2c34c156 100644 --- a/linux/drivers/media/video/cpia_pp.c +++ b/linux/drivers/media/video/cpia_pp.c @@ -62,7 +62,6 @@ static int cpia_pp_close(void *privdata); #define PPCPIA_PARPORT_OFF -2 #define PPCPIA_PARPORT_NONE -1 -#ifdef MODULE static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; static char *parport[PARPORT_MAX] = {NULL,}; @@ -72,11 +71,6 @@ MODULE_LICENSE("GPL"); module_param_array(parport, charp, NULL, 0); MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); -#else -static int parport_nr[PARPORT_MAX] __initdata = - {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; -static int parport_ptr = 0; -#endif struct pp_cam_entry { struct pardevice *pdev; @@ -827,7 +821,7 @@ static struct parport_driver cpia_pp_driver = { .detach = cpia_pp_detach, }; -static int cpia_pp_init(void) +static int __init cpia_pp_init(void) { printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); @@ -846,8 +840,7 @@ static int cpia_pp_init(void) return 0; } -#ifdef MODULE -int init_module(void) +static int __init cpia_init(void) { if (parport[0]) { /* The user gave some parameters. Let's see what they were. */ @@ -874,38 +867,11 @@ int init_module(void) return cpia_pp_init(); } -void cleanup_module(void) +static void __exit cpia_cleanup(void) { - parport_unregister_driver (&cpia_pp_driver); + parport_unregister_driver(&cpia_pp_driver); return; } -#else /* !MODULE */ - -static int __init cpia_pp_setup(char *str) -{ - int err; - - if (!strncmp(str, "parport", 7)) { - int n = simple_strtoul(str + 7, NULL, 10); - if (parport_ptr < PARPORT_MAX) { - parport_nr[parport_ptr++] = n; - } else { - LOG("too many ports, %s ignored.\n", str); - } - } else if (!strcmp(str, "auto")) { - parport_nr[0] = PPCPIA_PARPORT_AUTO; - } else if (!strcmp(str, "none")) { - parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; - } - - err=cpia_pp_init(); - if (err) - return err; - - return 1; -} - -__setup("cpia_pp=", cpia_pp_setup); - -#endif /* !MODULE */ +module_init(cpia_init); +module_exit(cpia_cleanup); diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c index bf67ec27d..da5dc6817 100644 --- a/linux/drivers/media/video/cx88/cx88-alsa.c +++ b/linux/drivers/media/video/cx88/cx88-alsa.c @@ -257,7 +257,8 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) cx_write(MO_AUD_INTSTAT, status); if (debug > 1 || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq aud", - cx88_aud_irqs, status, mask); + cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), + status, mask); /* risc op code error */ if (status & (1 << 16)) { printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index 774bcfed9..825334ef3 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1823,7 +1823,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) { 0x03, 0x0C }, }; - for (i = 0; i < 13; i++) { + for (i = 0; i < ARRAY_SIZE(init_bufs); i++) { msg.buf = init_bufs[i]; msg.len = (i != 12 ? 5 : 2); err = i2c_transfer(&core->i2c_adap, &msg, 1); @@ -1950,12 +1950,21 @@ void cx88_card_setup(struct cx88_core *core) if (0 == core->i2c_rc) { /* enable tuner */ int i; - static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; + static const u8 buffer [][2] = { + {0x10,0x12}, + {0x13,0x04}, + {0x16,0x00}, + {0x14,0x04}, + {0x17,0x00} + }; core->i2c_client.addr = 0x0a; - for (i = 0; i < 5; i++) - if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2)) - printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", + for (i = 0; i < ARRAY_SIZE(buffer); i++) + if (2 != i2c_master_send(&core->i2c_client, + buffer[i],2)) + printk(KERN_WARNING + "%s: Unable to enable " + "tuner(%i).\n", core->name, i); } break; diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c index 367dc3c7b..ba132d065 100644 --- a/linux/drivers/media/video/cx88/cx88-core.c +++ b/linux/drivers/media/video/cx88/cx88-core.c @@ -524,12 +524,12 @@ static char *cx88_pci_irqs[32] = { }; void cx88_print_irqbits(char *name, char *tag, char **strings, - u32 bits, u32 mask) + int len, u32 bits, u32 mask) { unsigned int i; printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); - for (i = 0; i < 32; i++) { + for (i = 0; i < len; i++) { if (!(bits & (1 << i))) continue; if (strings[i]) @@ -555,8 +555,8 @@ int cx88_core_irq(struct cx88_core *core, u32 status) } if (!handled) cx88_print_irqbits(core->name, "irq pci", - cx88_pci_irqs, status, - core->pci_irqmask); + cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs), + status, core->pci_irqmask); return handled; } diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index 2f60c957b..30fd0776a 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -1,3 +1,4 @@ + /* cx88-i2c.c -- all the i2c code is here @@ -206,7 +207,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i,rc; - for (i = 0; i < 128; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { c->addr = i; rc = i2c_master_recv(c,&buf,0); if (rc < 0) diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index cb642ca03..ce4ab476b 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -405,7 +405,8 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) if (debug || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq mpeg ", - cx88_mpeg_irqs, status, mask); + cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs), + status, mask); /* risc op code error */ if (status & (1 << 16)) { diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index 2e6259ceb..6eb6c370b 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -1836,7 +1836,8 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) cx_write(MO_VID_INTSTAT, status); if (irq_debug || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq vid", - cx88_vid_irqs, status, mask); + cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), + status, mask); /* risc op code error */ if (status & (1 << 16)) { diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 4719046e1..a35b46cab 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -545,7 +545,7 @@ struct cx8802_dev { /* cx88-core.c */ extern void cx88_print_irqbits(char *name, char *tag, char **strings, - u32 bits, u32 mask); + int len, u32 bits, u32 mask); extern int cx88_core_irq(struct cx88_core *core, u32 status); extern void cx88_wakeup(struct cx88_core *core, diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 4ee4cea10..ceb71f67c 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -544,7 +544,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i, rc; - for (i = 0; i < 128; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { c->addr = i; rc = i2c_master_recv(c, &buf, 0); if (rc < 0) diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c index d20bad700..8d0c49782 100644 --- a/linux/drivers/media/video/ir-kbd-i2c.c +++ b/linux/drivers/media/video/ir-kbd-i2c.c @@ -174,7 +174,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, return -EIO; } - for (start = 0; start<4; start++) { + for (start = 0; start < ARRAY_SIZE(b); start++) { if (b[start] == marker) { code=b[(start+parity_offset+1)%4]; parity=b[(start+parity_offset)%4]; diff --git a/linux/drivers/media/video/ov7670.c b/linux/drivers/media/video/ov7670.c index b033bf334..9ecf35fb1 100644 --- a/linux/drivers/media/video/ov7670.c +++ b/linux/drivers/media/video/ov7670.c @@ -164,6 +164,10 @@ MODULE_LICENSE("GPL"); #define REG_GFIX 0x69 /* Fix gain control */ +#define REG_REG76 0x76 /* OV's name */ +#define R76_BLKPCOR 0x80 /* Black pixel correction enable */ +#define R76_WHTPCOR 0x40 /* White pixel correction enable */ + #define REG_RGB444 0x8c /* RGB 444 control */ #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ #define R444_RGBX 0x01 /* Empty nibble at end */ @@ -257,7 +261,7 @@ static struct regval_list ov7670_default_regs[] = { /* Almost all of these are magic "reserved" values. */ { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, - { 0x16, 0x02 }, { REG_MVFP, 0x07|MVFP_MIRROR }, + { 0x16, 0x02 }, { REG_MVFP, 0x07 }, { 0x21, 0x02 }, { 0x22, 0x91 }, { 0x29, 0x07 }, { 0x33, 0x0b }, { 0x35, 0x0b }, { 0x37, 0x1d }, @@ -382,6 +386,13 @@ static struct regval_list ov7670_fmt_rgb444[] = { { 0xff, 0xff }, }; +static struct regval_list ov7670_fmt_raw[] = { + { REG_COM7, COM7_BAYER }, + { REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */ + { REG_COM16, 0x3d }, /* Edge enhancement, denoise */ + { REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */ + { 0xff, 0xff }, +}; @@ -506,32 +517,39 @@ static struct ov7670_format_struct { __u32 pixelformat; struct regval_list *regs; int cmatrix[CMATRIX_LEN]; + int bpp; /* Bytes per pixel */ } ov7670_formats[] = { { .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, .regs = ov7670_fmt_yuv422, .cmatrix = { 128, -128, 0, -34, -94, 128 }, + .bpp = 2, }, { .desc = "RGB 444", .pixelformat = V4L2_PIX_FMT_RGB444, .regs = ov7670_fmt_rgb444, .cmatrix = { 179, -179, 0, -61, -176, 228 }, + .bpp = 2, }, { .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, .regs = ov7670_fmt_rgb565, .cmatrix = { 179, -179, 0, -61, -176, 228 }, + .bpp = 2, + }, + { + .desc = "Raw RGB Bayer", + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .regs = ov7670_fmt_raw, + .cmatrix = { 0, 0, 0, 0, 0, 0 }, + .bpp = 1 }, }; -#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) +#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats) -/* - * All formats we support are 2 bytes/pixel. - */ -#define BYTES_PER_PIXEL 2 /* * Then there is the issue of window sizes. Try to capture the info here. @@ -708,7 +726,7 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, */ pix->width = wsize->width; pix->height = wsize->height; - pix->bytesperline = pix->width*BYTES_PER_PIXEL; + pix->bytesperline = pix->width*ov7670_formats[index].bpp; pix->sizeimage = pix->height*pix->bytesperline; return 0; } diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 5e8a2f498..31c74df34 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -1544,12 +1544,12 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_comp1, .vmux = 0, - .amux = LINE2, + .amux = LINE1, .gpio = 0x02, },{ .name = name_svideo, .vmux = 6, - .amux = LINE2, + .amux = LINE1, .gpio = 0x02, }}, .radio = { diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c index 1d41abee5..f470c85e7 100644 --- a/linux/drivers/media/video/saa7134/saa7134-i2c.c +++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c @@ -465,7 +465,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i,rc; - for (i = 0; i < 128; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { c->addr = i; rc = i2c_master_recv(c,&buf,0); if (rc < 0) diff --git a/linux/drivers/media/video/sn9c102/Makefile b/linux/drivers/media/video/sn9c102/Makefile index 30e3dfe53..a56d16f69 100644 --- a/linux/drivers/media/video/sn9c102/Makefile +++ b/linux/drivers/media/video/sn9c102/Makefile @@ -1,7 +1,14 @@ -sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ - sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \ - sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ - sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o \ + sn9c102_hv7131d.o \ + sn9c102_hv7131r.o \ + sn9c102_mi0343.o \ + sn9c102_mi0360.o \ + sn9c102_ov7630.o \ + sn9c102_ov7660.o \ + sn9c102_pas106b.o \ + sn9c102_pas202bcb.o \ + sn9c102_tas5110c1b.o \ + sn9c102_tas5110d.o \ + sn9c102_tas5130d1b.o obj-$(CONFIG_USB_SN9C102) += sn9c102.o - diff --git a/linux/drivers/media/video/sn9c102/sn9c102.h b/linux/drivers/media/video/sn9c102/sn9c102.h index d6af8fa87..dfb089b15 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102.h +++ b/linux/drivers/media/video/sn9c102/sn9c102.h @@ -81,8 +81,13 @@ enum sn9c102_stream_state { typedef char sn9c102_sof_header_t[62]; +struct sn9c102_sof_t { + sn9c102_sof_header_t header; + u16 bytesread; +}; + struct sn9c102_sysfs_attr { - u8 reg, i2c_reg; + u16 reg, i2c_reg; sn9c102_sof_header_t frame_header; }; @@ -115,7 +120,7 @@ struct sn9c102_device { struct v4l2_jpegcompression compression; struct sn9c102_sysfs_attr sysfs; - sn9c102_sof_header_t sof_header; + struct sn9c102_sof_t sof; u16 reg[384]; struct sn9c102_module_param module_param; @@ -189,8 +194,8 @@ do { \ if ((level) == 1 || (level) == 2) \ pr_info("sn9c102: " fmt "\n", ## args); \ else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ - __LINE__ , ## args); \ + pr_debug("sn9c102: [%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args); \ } \ } while (0) #else @@ -201,8 +206,8 @@ do { \ #undef PDBG #define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args) +dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \ + __LINE__ , ## args) #undef PDBGG #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c index a02d43ece..c8bcdc33f 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_core.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c @@ -44,11 +44,12 @@ /*****************************************************************************/ #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" -#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" +#define SN9C102_MODULE_ALIAS "sn9c1xx" +#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.34" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34) +#define SN9C102_MODULE_VERSION "1:1.39" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 39) /*****************************************************************************/ @@ -56,6 +57,7 @@ MODULE_DEVICE_TABLE(usb, sn9c102_id_table); MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); MODULE_DESCRIPTION(SN9C102_MODULE_NAME); +MODULE_ALIAS(SN9C102_MODULE_ALIAS); MODULE_VERSION(SN9C102_MODULE_VERSION); MODULE_LICENSE(SN9C102_MODULE_LICENSE); @@ -106,8 +108,7 @@ MODULE_PARM_DESC(debug, "\n1 = critical errors" "\n2 = significant informations" "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only, when only " - "one device is used." + "\nLevel 3 is useful for testing only." "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." "\n"); #endif @@ -121,8 +122,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, struct v4l2_pix_format* p = &(cam->sensor.pix_format); struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; + (p->width * p->height * p->priv) / 8 : + (r->width * r->height * p->priv) / 8; void* buff = NULL; u32 i; @@ -485,18 +486,43 @@ static size_t sn9c102_sof_length(struct sn9c102_device* cam) static void* sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) { - char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; - size_t soflen = 0, i; + const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; + const char *m = mem; + size_t soflen = 0, i, j; soflen = sn9c102_sof_length(cam); - for (i = 0; (len >= soflen) && (i <= len - soflen); i++) - if (!memcmp(mem + i, sof_header, sizeof(sof_header))) { - memcpy(cam->sof_header, mem + i, - sizeof(sn9c102_sof_header_t)); - /* Skip the header */ - return mem + i + soflen; + for (i = 0; i < len; i++) { + size_t b; + + /* Read the variable part of the header */ + if (unlikely(cam->sof.bytesread >= sizeof(marker))) { + cam->sof.header[cam->sof.bytesread] = *(m+i); + if (++cam->sof.bytesread == soflen) { + cam->sof.bytesread = 0; + return mem + i; + } + continue; + } + + /* Search for the SOF marker (fixed part) in the header */ + for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) { + if (unlikely(i+j) == len) + return NULL; + if (*(m+i+j) == marker[cam->sof.bytesread]) { + cam->sof.header[cam->sof.bytesread] = *(m+i+j); + if (++cam->sof.bytesread == sizeof(marker)) { + PDBGG("Bytes to analyze: %zd. SOF " + "starts at byte #%zd", len, i); + i += j+1; + break; + } + } else { + cam->sof.bytesread = 0; + break; } + } + } return NULL; } @@ -513,10 +539,16 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) }; size_t i, j; + /* The EOF header does not exist in compressed data */ if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - return NULL; /* EOF header does not exist in compressed data */ + return NULL; + /* + The EOF header might cross the packet boundary, but this is not a + problem, since the end of a frame is determined by checking its size + in the first place. + */ for (i = 0; (len >= 4) && (i <= len - 4); i++) for (j = 0; j < ARRAY_SIZE(eof_header); j++) if (!memcmp(mem + i, eof_header[j], 4)) @@ -643,6 +675,7 @@ static void sn9c102_urb_complete(struct urb *urb) cam->stream = STREAM_OFF; if ((*f)) (*f)->state = F_QUEUED; + cam->sof.bytesread = 0; DBG(3, "Stream interrupted by application"); wake_up(&cam->wait_stream); } @@ -680,6 +713,7 @@ static void sn9c102_urb_complete(struct urb *urb) if (status) { DBG(3, "Error in isochronous frame"); (*f)->state = F_ERROR; + cam->sof.bytesread = 0; continue; } @@ -696,13 +730,13 @@ end_of_frame: if (eof) img = (eof > pos) ? eof - pos - 1 : 0; - if ((*f)->buf.bytesused+img > imagesize) { + if ((*f)->buf.bytesused + img > imagesize) { u32 b; b = (*f)->buf.bytesused + img - imagesize; img = imagesize - (*f)->buf.bytesused; - DBG(3, "Expected EOF not found: " - "video frame cut"); + PDBGG("Expected EOF not found: video " + "frame cut"); if (eof) DBG(3, "Exceeded limit: +%u " "bytes", (unsigned)(b)); @@ -723,11 +757,6 @@ end_of_frame: V4L2_PIX_FMT_JPEG) && eof)) { u32 b; - if (cam->sensor.pix_format.pixelformat - == V4L2_PIX_FMT_JPEG) - sn9c102_write_eoimarker(cam, - (*f)); - b = (*f)->buf.bytesused; (*f)->state = F_DONE; (*f)->buf.sequence= ++cam->frame_count; @@ -745,7 +774,7 @@ end_of_frame: spin_unlock(&cam->queue_lock); memcpy(cam->sysfs.frame_header, - cam->sof_header, soflen); + cam->sof.header, soflen); DBG(3, "Video frame captured: %lu " "bytes", (unsigned long)(b)); @@ -795,7 +824,13 @@ start_of_frame: V4L2_PIX_FMT_SN9C10X || cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) { - eof = sof - soflen; + if (sof - pos >= soflen) { + eof = sof - soflen; + } else { /* remove header */ + eof = pos; + (*f)->buf.bytesused -= + (soflen - (sof - pos)); + } goto end_of_frame; } else { DBG(3, "SOF before expected EOF after " @@ -882,6 +917,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam) } cam->frame_current = NULL; + cam->sof.bytesread = 0; for (i = 0; i < SN9C102_URBS; i++) { err = usb_submit_urb(cam->urb[i], GFP_KERNEL); @@ -963,9 +999,9 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) if (len < 6) { strncpy(str, buff, len); - str[len+1] = '\0'; + str[len] = '\0'; } else { - strncpy(str, buff, 4); + strncpy(str, buff, 6); str[6] = '\0'; } @@ -1066,7 +1102,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) count = sprintf(buf, "%d\n", val); - DBG(3, "Read bytes: %zd", count); + DBG(3, "Read bytes: %zd, value: %d", count, val); mutex_unlock(&sn9c102_sysfs_lock); @@ -1201,7 +1237,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) count = sprintf(buf, "%d\n", val); - DBG(3, "Read bytes: %zd", count); + DBG(3, "Read bytes: %zd, value: %d", count, val); mutex_unlock(&sn9c102_sysfs_lock); @@ -1481,10 +1517,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, case BRIDGE_SN9C101: case BRIDGE_SN9C102: case BRIDGE_SN9C103: - if (compression->quality == 0) + if (compression->quality == 0) err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17); - else if (compression->quality == 1) + else if (compression->quality == 1) err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17); break; @@ -1493,10 +1529,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, if (compression->quality == 0) { for (i = 0; i <= 63; i++) { err += sn9c102_write_reg(cam, - SN9C102_Y_QTABLE0[i], + SN9C102_Y_QTABLE1[i], 0x100 + i); err += sn9c102_write_reg(cam, - SN9C102_UV_QTABLE0[i], + SN9C102_UV_QTABLE1[i], 0x140 + i); } err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, @@ -1601,9 +1637,13 @@ static int sn9c102_init(struct sn9c102_device* cam) if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102 || cam->bridge == BRIDGE_SN9C103) { + if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) + s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8; cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; } else { + if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) + s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG; cam->compression.quality = cam->reg[0x18] & 0x40 ? 0 : 1; err += sn9c102_set_compression(cam, &cam->compression); @@ -1809,7 +1849,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) DBG(3, "Close and open the device again to choose " "the read method"); mutex_unlock(&cam->fileop_mutex); - return -EINVAL; + return -EBUSY; } if (cam->io == IO_NONE) { @@ -1849,16 +1889,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) return err; } } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) { + mutex_unlock(&cam->fileop_mutex); + return timeout; } else if (timeout == 0 && !(cam->state & DEV_DISCONNECTED)) { DBG(1, "Video frame timeout elapsed"); @@ -2005,7 +2045,12 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) return -EIO; } - if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || + if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { + mutex_unlock(&cam->fileop_mutex); + return -EACCES; + } + + if (cam->io != IO_MMAP || size != PAGE_ALIGN(cam->frame[0].buf.length)) { mutex_unlock(&cam->fileop_mutex); return -EINVAL; @@ -2271,7 +2316,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_CROP failed. " "Unmap the buffers first."); - return -EINVAL; + return -EBUSY; } /* Preserve R,G or B origin */ @@ -2414,8 +2459,8 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) case BRIDGE_SN9C101: case BRIDGE_SN9C102: case BRIDGE_SN9C103: - strcpy(fmtd.description, "compressed"); - fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; + strcpy(fmtd.description, "compressed"); + fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; break; case BRIDGE_SN9C105: case BRIDGE_SN9C120: @@ -2449,8 +2494,10 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X || - pfmt->pixelformat==V4L2_PIX_FMT_JPEG) + pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? + V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; + pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X || + pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? 0 : (pfmt->width * pfmt->priv) / 8; pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); pfmt->field = V4L2_FIELD_NONE; @@ -2525,9 +2572,9 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, case BRIDGE_SN9C101: case BRIDGE_SN9C102: case BRIDGE_SN9C103: - if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; + if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && + pix->pixelformat != V4L2_PIX_FMT_SBGGR8) + pix->pixelformat = pfmt->pixelformat; break; case BRIDGE_SN9C105: case BRIDGE_SN9C120: @@ -2537,7 +2584,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, break; } pix->priv = pfmt->priv; /* bpp */ - pix->colorspace = pfmt->colorspace; + pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ? + V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || pix->pixelformat == V4L2_PIX_FMT_JPEG) ? 0 : (pix->width * pix->priv) / 8; @@ -2555,7 +2603,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_FMT failed. Unmap the " "buffers first."); - return -EINVAL; + return -EBUSY; } if (cam->stream == STREAM_ON) @@ -2670,14 +2718,14 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) if (cam->io == IO_READ) { DBG(3, "Close and open the device again to choose the mmap " "I/O method"); - return -EINVAL; + return -EBUSY; } for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " "still mapped."); - return -EINVAL; + return -EBUSY; } if (cam->stream == STREAM_ON) @@ -2789,15 +2837,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, if (err) return err; } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) + return timeout; else if (timeout == 0 && !(cam->state & DEV_DISCONNECTED)) { DBG(1, "Video frame timeout elapsed"); @@ -2841,9 +2889,6 @@ sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; - if (list_empty(&cam->inqueue)) - return -EINVAL; - cam->stream = STREAM_ON; DBG(3, "Stream on"); @@ -3170,8 +3215,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) r = sn9c102_read_reg(cam, 0x00); if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { - DBG(1, "Sorry, this is not a SN9C1xx based camera " - "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + DBG(1, "Sorry, this is not a SN9C1xx-based camera " + "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); err = -ENODEV; goto fail; } @@ -3181,19 +3226,19 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) case BRIDGE_SN9C101: case BRIDGE_SN9C102: DBG(2, "SN9C10[12] PC Camera Controller detected " - "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; case BRIDGE_SN9C103: DBG(2, "SN9C103 PC Camera Controller detected " - "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; case BRIDGE_SN9C105: DBG(2, "SN9C105 PC Camera Controller detected " - "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; case BRIDGE_SN9C120: DBG(2, "SN9C120 PC Camera Controller detected " - "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; } @@ -3264,6 +3309,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) "device controlling. Error #%d", err); #else DBG(2, "Optional device control through 'sysfs' interface disabled"); + DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " + "configuration option to enable it."); #endif usb_set_intfdata(intf, cam); diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h index 3a682eca6..f49bd8c5b 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -89,16 +89,22 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, + { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, + { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, /* SN9C120 */ + { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, + { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, + { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, + { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, @@ -114,12 +120,15 @@ static const struct usb_device_id sn9c102_id_table[] = { Functions must return 0 on success, the appropriate error otherwise. */ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); +extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); +extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); +extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); /* @@ -128,13 +137,16 @@ extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); the order of the list below, from top to bottom. */ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { + &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ + &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ + &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ - &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ + &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ NULL, }; diff --git a/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c index 7ae368f60..9b2e2d68c 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c @@ -22,9 +22,6 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor hv7131d; - - static int hv7131d_init(struct sn9c102_device* cam) { int err = 0; @@ -153,7 +150,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor hv7131d = { .name = "HV7131D", .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_2WIRES, @@ -263,7 +260,7 @@ int sn9c102_probe_hv7131d(struct sn9c102_device* cam) if (r0 < 0 || r1 < 0) return -EIO; - if (r0 != 0x00 && r1 != 0x04) + if (r0 != 0x00 || r1 != 0x04) return -ENODEV; sn9c102_attach_sensor(cam, &hv7131d); diff --git a/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c new file mode 100644 index 000000000..c4a3e3991 --- /dev/null +++ b/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c @@ -0,0 +1,458 @@ +/*************************************************************************** + * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * + * Controllers * + * * + * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static int hv7131r_init(struct sn9c102_device* cam) +{ + int err = 0; + + switch (sn9c102_get_bridge(cam)) { + case BRIDGE_SN9C103: + err += sn9c102_write_reg(cam, 0x00, 0x03); + err += sn9c102_write_reg(cam, 0x1a, 0x04); + err += sn9c102_write_reg(cam, 0x20, 0x05); + err += sn9c102_write_reg(cam, 0x20, 0x06); + err += sn9c102_write_reg(cam, 0x03, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0a, 0x18); + err += sn9c102_write_reg(cam, 0xf0, 0x19); + err += sn9c102_write_reg(cam, 0x1d, 0x1a); + err += sn9c102_write_reg(cam, 0x10, 0x1b); + err += sn9c102_write_reg(cam, 0x02, 0x1c); + err += sn9c102_write_reg(cam, 0x03, 0x1d); + err += sn9c102_write_reg(cam, 0x0f, 0x1e); + err += sn9c102_write_reg(cam, 0x0c, 0x1f); + err += sn9c102_write_reg(cam, 0x00, 0x20); + err += sn9c102_write_reg(cam, 0x10, 0x21); + err += sn9c102_write_reg(cam, 0x20, 0x22); + err += sn9c102_write_reg(cam, 0x30, 0x23); + err += sn9c102_write_reg(cam, 0x40, 0x24); + err += sn9c102_write_reg(cam, 0x50, 0x25); + err += sn9c102_write_reg(cam, 0x60, 0x26); + err += sn9c102_write_reg(cam, 0x70, 0x27); + err += sn9c102_write_reg(cam, 0x80, 0x28); + err += sn9c102_write_reg(cam, 0x90, 0x29); + err += sn9c102_write_reg(cam, 0xa0, 0x2a); + err += sn9c102_write_reg(cam, 0xb0, 0x2b); + err += sn9c102_write_reg(cam, 0xc0, 0x2c); + err += sn9c102_write_reg(cam, 0xd0, 0x2d); + err += sn9c102_write_reg(cam, 0xe0, 0x2e); + err += sn9c102_write_reg(cam, 0xf0, 0x2f); + err += sn9c102_write_reg(cam, 0xff, 0x30); + break; + case BRIDGE_SN9C105: + case BRIDGE_SN9C120: + err += sn9c102_write_reg(cam, 0x44, 0x01); + err += sn9c102_write_reg(cam, 0x40, 0x02); + err += sn9c102_write_reg(cam, 0x00, 0x03); + err += sn9c102_write_reg(cam, 0x1a, 0x04); + err += sn9c102_write_reg(cam, 0x44, 0x05); + err += sn9c102_write_reg(cam, 0x3e, 0x06); + err += sn9c102_write_reg(cam, 0x1a, 0x07); + err += sn9c102_write_reg(cam, 0x03, 0x10); + err += sn9c102_write_reg(cam, 0x08, 0x14); + err += sn9c102_write_reg(cam, 0xa3, 0x17); + err += sn9c102_write_reg(cam, 0x4b, 0x18); + err += sn9c102_write_reg(cam, 0x00, 0x19); + err += sn9c102_write_reg(cam, 0x1d, 0x1a); + err += sn9c102_write_reg(cam, 0x10, 0x1b); + err += sn9c102_write_reg(cam, 0x02, 0x1c); + err += sn9c102_write_reg(cam, 0x03, 0x1d); + err += sn9c102_write_reg(cam, 0x0f, 0x1e); + err += sn9c102_write_reg(cam, 0x0c, 0x1f); + err += sn9c102_write_reg(cam, 0x00, 0x20); + err += sn9c102_write_reg(cam, 0x29, 0x21); + err += sn9c102_write_reg(cam, 0x40, 0x22); + err += sn9c102_write_reg(cam, 0x54, 0x23); + err += sn9c102_write_reg(cam, 0x66, 0x24); + err += sn9c102_write_reg(cam, 0x76, 0x25); + err += sn9c102_write_reg(cam, 0x85, 0x26); + err += sn9c102_write_reg(cam, 0x94, 0x27); + err += sn9c102_write_reg(cam, 0xa1, 0x28); + err += sn9c102_write_reg(cam, 0xae, 0x29); + err += sn9c102_write_reg(cam, 0xbb, 0x2a); + err += sn9c102_write_reg(cam, 0xc7, 0x2b); + err += sn9c102_write_reg(cam, 0xd3, 0x2c); + err += sn9c102_write_reg(cam, 0xde, 0x2d); + err += sn9c102_write_reg(cam, 0xea, 0x2e); + err += sn9c102_write_reg(cam, 0xf4, 0x2f); + err += sn9c102_write_reg(cam, 0xff, 0x30); + err += sn9c102_write_reg(cam, 0x00, 0x3F); + err += sn9c102_write_reg(cam, 0xC7, 0x40); + err += sn9c102_write_reg(cam, 0x01, 0x41); + err += sn9c102_write_reg(cam, 0x44, 0x42); + err += sn9c102_write_reg(cam, 0x00, 0x43); + err += sn9c102_write_reg(cam, 0x44, 0x44); + err += sn9c102_write_reg(cam, 0x00, 0x45); + err += sn9c102_write_reg(cam, 0x44, 0x46); + err += sn9c102_write_reg(cam, 0x00, 0x47); + err += sn9c102_write_reg(cam, 0xC7, 0x48); + err += sn9c102_write_reg(cam, 0x01, 0x49); + err += sn9c102_write_reg(cam, 0xC7, 0x4A); + err += sn9c102_write_reg(cam, 0x01, 0x4B); + err += sn9c102_write_reg(cam, 0xC7, 0x4C); + err += sn9c102_write_reg(cam, 0x01, 0x4D); + err += sn9c102_write_reg(cam, 0x44, 0x4E); + err += sn9c102_write_reg(cam, 0x00, 0x4F); + err += sn9c102_write_reg(cam, 0x44, 0x50); + err += sn9c102_write_reg(cam, 0x00, 0x51); + err += sn9c102_write_reg(cam, 0x44, 0x52); + err += sn9c102_write_reg(cam, 0x00, 0x53); + err += sn9c102_write_reg(cam, 0xC7, 0x54); + err += sn9c102_write_reg(cam, 0x01, 0x55); + err += sn9c102_write_reg(cam, 0xC7, 0x56); + err += sn9c102_write_reg(cam, 0x01, 0x57); + err += sn9c102_write_reg(cam, 0xC7, 0x58); + err += sn9c102_write_reg(cam, 0x01, 0x59); + err += sn9c102_write_reg(cam, 0x44, 0x5A); + err += sn9c102_write_reg(cam, 0x00, 0x5B); + err += sn9c102_write_reg(cam, 0x44, 0x5C); + err += sn9c102_write_reg(cam, 0x00, 0x5D); + err += sn9c102_write_reg(cam, 0x44, 0x5E); + err += sn9c102_write_reg(cam, 0x00, 0x5F); + err += sn9c102_write_reg(cam, 0xC7, 0x60); + err += sn9c102_write_reg(cam, 0x01, 0x61); + err += sn9c102_write_reg(cam, 0xC7, 0x62); + err += sn9c102_write_reg(cam, 0x01, 0x63); + err += sn9c102_write_reg(cam, 0xC7, 0x64); + err += sn9c102_write_reg(cam, 0x01, 0x65); + err += sn9c102_write_reg(cam, 0x44, 0x66); + err += sn9c102_write_reg(cam, 0x00, 0x67); + err += sn9c102_write_reg(cam, 0x44, 0x68); + err += sn9c102_write_reg(cam, 0x00, 0x69); + err += sn9c102_write_reg(cam, 0x44, 0x6A); + err += sn9c102_write_reg(cam, 0x00, 0x6B); + err += sn9c102_write_reg(cam, 0xC7, 0x6C); + err += sn9c102_write_reg(cam, 0x01, 0x6D); + err += sn9c102_write_reg(cam, 0xC7, 0x6E); + err += sn9c102_write_reg(cam, 0x01, 0x6F); + err += sn9c102_write_reg(cam, 0xC7, 0x70); + err += sn9c102_write_reg(cam, 0x01, 0x71); + err += sn9c102_write_reg(cam, 0x44, 0x72); + err += sn9c102_write_reg(cam, 0x00, 0x73); + err += sn9c102_write_reg(cam, 0x44, 0x74); + err += sn9c102_write_reg(cam, 0x00, 0x75); + err += sn9c102_write_reg(cam, 0x44, 0x76); + err += sn9c102_write_reg(cam, 0x00, 0x77); + err += sn9c102_write_reg(cam, 0xC7, 0x78); + err += sn9c102_write_reg(cam, 0x01, 0x79); + err += sn9c102_write_reg(cam, 0xC7, 0x7A); + err += sn9c102_write_reg(cam, 0x01, 0x7B); + err += sn9c102_write_reg(cam, 0xC7, 0x7C); + err += sn9c102_write_reg(cam, 0x01, 0x7D); + err += sn9c102_write_reg(cam, 0x44, 0x7E); + err += sn9c102_write_reg(cam, 0x00, 0x7F); + err += sn9c102_write_reg(cam, 0x14, 0x84); + err += sn9c102_write_reg(cam, 0x00, 0x85); + err += sn9c102_write_reg(cam, 0x27, 0x86); + err += sn9c102_write_reg(cam, 0x00, 0x87); + err += sn9c102_write_reg(cam, 0x07, 0x88); + err += sn9c102_write_reg(cam, 0x00, 0x89); + err += sn9c102_write_reg(cam, 0xEC, 0x8A); + err += sn9c102_write_reg(cam, 0x0f, 0x8B); + err += sn9c102_write_reg(cam, 0xD8, 0x8C); + err += sn9c102_write_reg(cam, 0x0f, 0x8D); + err += sn9c102_write_reg(cam, 0x3D, 0x8E); + err += sn9c102_write_reg(cam, 0x00, 0x8F); + err += sn9c102_write_reg(cam, 0x3D, 0x90); + err += sn9c102_write_reg(cam, 0x00, 0x91); + err += sn9c102_write_reg(cam, 0xCD, 0x92); + err += sn9c102_write_reg(cam, 0x0f, 0x93); + err += sn9c102_write_reg(cam, 0xf7, 0x94); + err += sn9c102_write_reg(cam, 0x0f, 0x95); + err += sn9c102_write_reg(cam, 0x0C, 0x96); + err += sn9c102_write_reg(cam, 0x00, 0x97); + err += sn9c102_write_reg(cam, 0x00, 0x98); + err += sn9c102_write_reg(cam, 0x66, 0x99); + err += sn9c102_write_reg(cam, 0x05, 0x9A); + err += sn9c102_write_reg(cam, 0x00, 0x9B); + err += sn9c102_write_reg(cam, 0x04, 0x9C); + err += sn9c102_write_reg(cam, 0x00, 0x9D); + err += sn9c102_write_reg(cam, 0x08, 0x9E); + err += sn9c102_write_reg(cam, 0x00, 0x9F); + err += sn9c102_write_reg(cam, 0x2D, 0xC0); + err += sn9c102_write_reg(cam, 0x2D, 0xC1); + err += sn9c102_write_reg(cam, 0x3A, 0xC2); + err += sn9c102_write_reg(cam, 0x05, 0xC3); + err += sn9c102_write_reg(cam, 0x04, 0xC4); + err += sn9c102_write_reg(cam, 0x3F, 0xC5); + err += sn9c102_write_reg(cam, 0x00, 0xC6); + err += sn9c102_write_reg(cam, 0x00, 0xC7); + err += sn9c102_write_reg(cam, 0x50, 0xC8); + err += sn9c102_write_reg(cam, 0x3C, 0xC9); + err += sn9c102_write_reg(cam, 0x28, 0xCA); + err += sn9c102_write_reg(cam, 0xD8, 0xCB); + err += sn9c102_write_reg(cam, 0x14, 0xCC); + err += sn9c102_write_reg(cam, 0xEC, 0xCD); + err += sn9c102_write_reg(cam, 0x32, 0xCE); + err += sn9c102_write_reg(cam, 0xDD, 0xCF); + err += sn9c102_write_reg(cam, 0x32, 0xD0); + err += sn9c102_write_reg(cam, 0xDD, 0xD1); + err += sn9c102_write_reg(cam, 0x6A, 0xD2); + err += sn9c102_write_reg(cam, 0x50, 0xD3); + err += sn9c102_write_reg(cam, 0x00, 0xD4); + err += sn9c102_write_reg(cam, 0x00, 0xD5); + err += sn9c102_write_reg(cam, 0x00, 0xD6); + break; + default: + break; + } + + err += sn9c102_i2c_write(cam, 0x20, 0x00); + err += sn9c102_i2c_write(cam, 0x21, 0xd6); + err += sn9c102_i2c_write(cam, 0x25, 0x06); + + return err; +} + + +static int hv7131r_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_GAIN: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) + return -EIO; + return 0; + case V4L2_CID_RED_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) + return -EIO; + ctrl->value = ctrl->value & 0x3f; + return 0; + case V4L2_CID_BLUE_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) + return -EIO; + ctrl->value = ctrl->value & 0x3f; + return 0; + case SN9C102_V4L2_CID_GREEN_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) + return -EIO; + ctrl->value = ctrl->value & 0x3f; + return 0; + case V4L2_CID_BLACK_LEVEL: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0) + return -EIO; + ctrl->value = (ctrl->value & 0x08) ? 1 : 0; + return 0; + default: + return -EINVAL; + } +} + + +static int hv7131r_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x30, ctrl->value); + break; + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x31, ctrl->value); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x33, ctrl->value); + break; + case SN9C102_V4L2_CID_GREEN_BALANCE: + err += sn9c102_i2c_write(cam, 0x32, ctrl->value); + break; + case V4L2_CID_BLACK_LEVEL: + { + int r = sn9c102_i2c_read(cam, 0x01); + if (r < 0) + return -EIO; + err += sn9c102_i2c_write(cam, 0x01, + (ctrl->value<<3) | (r&0xf7)); + } + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + + +static int hv7131r_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static int hv7131r_set_pix_format(struct sn9c102_device* cam, + const struct v4l2_pix_format* pix) +{ + int err = 0; + + switch (sn9c102_get_bridge(cam)) { + case BRIDGE_SN9C103: + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { + err += sn9c102_write_reg(cam, 0xa0, 0x19); + err += sn9c102_i2c_write(cam, 0x01, 0x04); + } else { + err += sn9c102_write_reg(cam, 0x30, 0x19); + err += sn9c102_i2c_write(cam, 0x01, 0x04); + } + break; + case BRIDGE_SN9C105: + case BRIDGE_SN9C120: + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { + err += sn9c102_write_reg(cam, 0xa5, 0x17); + err += sn9c102_i2c_write(cam, 0x01, 0x24); + } else { + err += sn9c102_write_reg(cam, 0xa3, 0x17); + err += sn9c102_i2c_write(cam, 0x01, 0x04); + } + break; + default: + break; + } + + return err; +} + + +static struct sn9c102_sensor hv7131r = { + .name = "HV7131R", + .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", + .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, + .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x11, + .init = &hv7131r_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x40, + .flags = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x08, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x1a, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x2f, + .flags = 0, + }, + { + .id = V4L2_CID_BLACK_LEVEL, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto black level compensation", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + }, + .get_ctrl = &hv7131r_get_ctrl, + .set_ctrl = &hv7131r_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &hv7131r_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &hv7131r_set_pix_format +}; + + +int sn9c102_probe_hv7131r(struct sn9c102_device* cam) +{ + int devid, err = 0; + + err += sn9c102_write_reg(cam, 0x09, 0x01); + err += sn9c102_write_reg(cam, 0x44, 0x02); + err += sn9c102_write_reg(cam, 0x34, 0x01); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x34, 0x01); + err += sn9c102_write_reg(cam, 0x46, 0x01); + if (err) + return -EIO; + + devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00); + if (devid < 0) + return -EIO; + + if (devid != 0x02) + return -ENODEV; + + sn9c102_attach_sensor(cam, &hv7131r); + + return 0; +} diff --git a/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c b/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c index a33d1bc10..441156d61 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c @@ -22,12 +22,9 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor mi0343; -static u8 mi0343_i2c_data[5+1]; - - static int mi0343_init(struct sn9c102_device* cam) { + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); int err = 0; err += sn9c102_write_reg(cam, 0x00, 0x10); @@ -38,20 +35,20 @@ static int mi0343_init(struct sn9c102_device* cam) err += sn9c102_write_reg(cam, 0x07, 0x18); err += sn9c102_write_reg(cam, 0xa0, 0x19); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x0d, 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x0d, 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x03, 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x04, 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x05, 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x06, 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x62, 0x04, 0x9a, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, + 0x01, 0xe1, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, + 0x02, 0x81, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, + 0x00, 0x17, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, + 0x00, 0x11, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, + 0x04, 0x9a, 0, 0); return err; } @@ -60,43 +57,46 @@ static int mi0343_init(struct sn9c102_device* cam) static int mi0343_get_ctrl(struct sn9c102_device* cam, struct v4l2_control* ctrl) { + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + u8 data[5+1]; + switch (ctrl->id) { case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x09, 2+1, mi0343_i2c_data) < 0) + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, + 2+1, data) < 0) return -EIO; - ctrl->value = mi0343_i2c_data[2]; + ctrl->value = data[2]; return 0; case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x35, 2+1, mi0343_i2c_data) < 0) + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, + 2+1, data) < 0) return -EIO; break; case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x20, 2+1, mi0343_i2c_data) < 0) + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, + 2+1, data) < 0) return -EIO; - ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0; + ctrl->value = data[3] & 0x20 ? 1 : 0; return 0; case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x20, 2+1, mi0343_i2c_data) < 0) + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, + 2+1, data) < 0) return -EIO; - ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0; + ctrl->value = data[3] & 0x80 ? 1 : 0; return 0; case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x2d, 2+1, mi0343_i2c_data) < 0) + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, + 2+1, data) < 0) return -EIO; break; case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x2c, 2+1, mi0343_i2c_data) < 0) + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, + 2+1, data) < 0) return -EIO; break; case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x2e, 2+1, mi0343_i2c_data) < 0) + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, + 2+1, data) < 0) return -EIO; break; default: @@ -108,7 +108,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, case V4L2_CID_RED_BALANCE: case V4L2_CID_BLUE_BALANCE: case SN9C102_V4L2_CID_GREEN_BALANCE: - ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8); + ctrl->value = data[3] | (data[2] << 8); if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) ctrl->value -= 0x10; else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) @@ -124,6 +124,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, static int mi0343_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); u16 reg = 0; int err = 0; @@ -143,50 +144,42 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x09, ctrl->value, 0x00, 0, 0); break; case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x35, reg >> 8, reg & 0xff, 0, 0); break; case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, ctrl->value ? 0x40:0x00, ctrl->value ? 0x20:0x00, 0, 0); break; case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, ctrl->value ? 0x80:0x00, ctrl->value ? 0x80:0x00, 0, 0); break; case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x2d, reg >> 8, reg & 0xff, 0, 0); break; case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x2c, reg >> 8, reg & 0xff, 0, 0); break; case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x2b, reg >> 8, reg & 0xff, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x2e, reg >> 8, reg & 0xff, 0, 0); break; @@ -216,16 +209,15 @@ static int mi0343_set_crop(struct sn9c102_device* cam, static int mi0343_set_pix_format(struct sn9c102_device* cam, const struct v4l2_pix_format* pix) { + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); int err = 0; if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0a, 0x00, 0x03, 0, 0); err += sn9c102_write_reg(cam, 0x20, 0x19); } else { - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0a, 0x00, 0x05, 0, 0); err += sn9c102_write_reg(cam, 0xa0, 0x19); } @@ -237,7 +229,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor mi0343 = { .name = "MI-0343", .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_2WIRES, .i2c_slave_id = 0x5d, @@ -343,6 +335,7 @@ static struct sn9c102_sensor mi0343 = { int sn9c102_probe_mi0343(struct sn9c102_device* cam) { + u8 data[5+1]; int err = 0; err += sn9c102_write_reg(cam, 0x01, 0x01); @@ -352,10 +345,10 @@ int sn9c102_probe_mi0343(struct sn9c102_device* cam) return -EIO; if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, - 2, mi0343_i2c_data) < 0) + 2, data) < 0) return -EIO; - if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3) + if (data[4] != 0x32 || data[3] != 0xe3) return -ENODEV; sn9c102_attach_sensor(cam, &mi0343); diff --git a/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c b/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c new file mode 100644 index 000000000..7154dd053 --- /dev/null +++ b/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c @@ -0,0 +1,353 @@ +/*************************************************************************** + * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera * + * Controllers * + * * + * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static int mi0360_init(struct sn9c102_device* cam) +{ + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x0a, 0x14); + err += sn9c102_write_reg(cam, 0x40, 0x01); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x07, 0x18); + err += sn9c102_write_reg(cam, 0xa0, 0x19); + err += sn9c102_write_reg(cam, 0x02, 0x1c); + err += sn9c102_write_reg(cam, 0x03, 0x1d); + err += sn9c102_write_reg(cam, 0x0f, 0x1e); + err += sn9c102_write_reg(cam, 0x0c, 0x1f); + err += sn9c102_write_reg(cam, 0x00, 0x20); + err += sn9c102_write_reg(cam, 0x10, 0x21); + err += sn9c102_write_reg(cam, 0x20, 0x22); + err += sn9c102_write_reg(cam, 0x30, 0x23); + err += sn9c102_write_reg(cam, 0x40, 0x24); + err += sn9c102_write_reg(cam, 0x50, 0x25); + err += sn9c102_write_reg(cam, 0x60, 0x26); + err += sn9c102_write_reg(cam, 0x70, 0x27); + err += sn9c102_write_reg(cam, 0x80, 0x28); + err += sn9c102_write_reg(cam, 0x90, 0x29); + err += sn9c102_write_reg(cam, 0xa0, 0x2a); + err += sn9c102_write_reg(cam, 0xb0, 0x2b); + err += sn9c102_write_reg(cam, 0xc0, 0x2c); + err += sn9c102_write_reg(cam, 0xd0, 0x2d); + err += sn9c102_write_reg(cam, 0xe0, 0x2e); + err += sn9c102_write_reg(cam, 0xf0, 0x2f); + err += sn9c102_write_reg(cam, 0xff, 0x30); + + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, + 0x01, 0xe1, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, + 0x02, 0x81, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, + 0x00, 0x17, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, + 0x00, 0x11, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, + 0x04, 0x9a, 0, 0); + + return err; +} + + +static int mi0360_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + u8 data[5+1]; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, + 2+1, data) < 0) + return -EIO; + ctrl->value = data[2]; + return 0; + case V4L2_CID_GAIN: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, + 2+1, data) < 0) + return -EIO; + ctrl->value = data[3]; + return 0; + case V4L2_CID_RED_BALANCE: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, + 2+1, data) < 0) + return -EIO; + ctrl->value = data[3]; + return 0; + case V4L2_CID_BLUE_BALANCE: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, + 2+1, data) < 0) + return -EIO; + ctrl->value = data[3]; + return 0; + case SN9C102_V4L2_CID_GREEN_BALANCE: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, + 2+1, data) < 0) + return -EIO; + ctrl->value = data[3]; + return 0; + case V4L2_CID_HFLIP: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, + 2+1, data) < 0) + return -EIO; + ctrl->value = data[3] & 0x20 ? 1 : 0; + return 0; + case V4L2_CID_VFLIP: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, + 2+1, data) < 0) + return -EIO; + ctrl->value = data[3] & 0x80 ? 1 : 0; + return 0; + default: + return -EINVAL; + } + + return 0; +} + + +static int mi0360_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x09, ctrl->value, 0x00, + 0, 0); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x35, 0x03, ctrl->value, + 0, 0); + break; + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x2c, 0x03, ctrl->value, + 0, 0); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x2d, 0x03, ctrl->value, + 0, 0); + break; + case SN9C102_V4L2_CID_GREEN_BALANCE: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x2b, 0x03, ctrl->value, + 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x2e, 0x03, ctrl->value, + 0, 0); + break; + case V4L2_CID_HFLIP: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x20, ctrl->value ? 0x40:0x00, + ctrl->value ? 0x20:0x00, + 0, 0); + break; + case V4L2_CID_VFLIP: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x20, ctrl->value ? 0x80:0x00, + ctrl->value ? 0x80:0x00, + 0, 0); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + + +static int mi0360_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static int mi0360_set_pix_format(struct sn9c102_device* cam, + const struct v4l2_pix_format* pix) +{ + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x0a, 0x00, 0x02, 0, 0); + err += sn9c102_write_reg(cam, 0x20, 0x19); + } else { + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x0a, 0x00, 0x05, 0, 0); + err += sn9c102_write_reg(cam, 0x60, 0x19); + } + + return err; +} + + +static struct sn9c102_sensor mi0360 = { + .name = "MI-0360", + .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", + .supported_bridge = BRIDGE_SN9C103, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x5d, + .init = &mi0360_init, + .qctrl = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x05, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x7f, + .step = 0x01, + .default_value = 0x25, + .flags = 0, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x7f, + .step = 0x01, + .default_value = 0x0f, + .flags = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x7f, + .step = 0x01, + .default_value = 0x32, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0x7f, + .step = 0x01, + .default_value = 0x25, + .flags = 0, + }, + }, + .get_ctrl = &mi0360_get_ctrl, + .set_ctrl = &mi0360_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &mi0360_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &mi0360_set_pix_format +}; + + +int sn9c102_probe_mi0360(struct sn9c102_device* cam) +{ + u8 data[5+1]; + int err = 0; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); + if (err) + return -EIO; + + if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, + 2+1, data) < 0) + return -EIO; + + if (data[2] != 0x82 || data[3] != 0x43) + return -ENODEV; + + sn9c102_attach_sensor(cam, &mi0360); + + return 0; +} diff --git a/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c b/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c index 7df09ff38..ad9fb2ca2 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c @@ -22,9 +22,6 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor ov7630; - - static int ov7630_init(struct sn9c102_device* cam) { int err = 0; @@ -32,21 +29,21 @@ static int ov7630_init(struct sn9c102_device* cam) switch (sn9c102_get_bridge(cam)) { case BRIDGE_SN9C101: case BRIDGE_SN9C102: - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x60, 0x17); - err += sn9c102_write_reg(cam, 0x0f, 0x18); - err += sn9c102_write_reg(cam, 0x50, 0x19); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0f, 0x18); + err += sn9c102_write_reg(cam, 0x50, 0x19); err += sn9c102_i2c_write(cam, 0x12, 0x8d); err += sn9c102_i2c_write(cam, 0x12, 0x0d); err += sn9c102_i2c_write(cam, 0x11, 0x00); - err += sn9c102_i2c_write(cam, 0x15, 0x34); - err += sn9c102_i2c_write(cam, 0x16, 0x03); - err += sn9c102_i2c_write(cam, 0x17, 0x1c); - err += sn9c102_i2c_write(cam, 0x18, 0xbd); - err += sn9c102_i2c_write(cam, 0x19, 0x06); - err += sn9c102_i2c_write(cam, 0x1a, 0xf6); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); + err += sn9c102_i2c_write(cam, 0x15, 0x35); + err += sn9c102_i2c_write(cam, 0x16, 0x03); + err += sn9c102_i2c_write(cam, 0x17, 0x1c); + err += sn9c102_i2c_write(cam, 0x18, 0xbd); + err += sn9c102_i2c_write(cam, 0x19, 0x06); + err += sn9c102_i2c_write(cam, 0x1a, 0xf6); + err += sn9c102_i2c_write(cam, 0x1b, 0x04); err += sn9c102_i2c_write(cam, 0x20, 0x44); err += sn9c102_i2c_write(cam, 0x23, 0xee); err += sn9c102_i2c_write(cam, 0x26, 0xa0); @@ -108,23 +105,23 @@ static int ov7630_init(struct sn9c102_device* cam) err += sn9c102_i2c_write(cam, 0x11, 0x01); err += sn9c102_i2c_write(cam, 0x1b, 0x04); err += sn9c102_i2c_write(cam, 0x20, 0x44); - err += sn9c102_i2c_write(cam, 0x23, 0xee); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0x9a); + err += sn9c102_i2c_write(cam, 0x23, 0xee); + err += sn9c102_i2c_write(cam, 0x26, 0xa0); + err += sn9c102_i2c_write(cam, 0x27, 0x9a); err += sn9c102_i2c_write(cam, 0x28, 0x20); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2f, 0x3d); - err += sn9c102_i2c_write(cam, 0x30, 0x24); - err += sn9c102_i2c_write(cam, 0x32, 0x86); - err += sn9c102_i2c_write(cam, 0x60, 0xa9); - err += sn9c102_i2c_write(cam, 0x61, 0x42); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x88); - err += sn9c102_i2c_write(cam, 0x70, 0x0b); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x74, 0x21); - err += sn9c102_i2c_write(cam, 0x7d, 0xf7); + err += sn9c102_i2c_write(cam, 0x29, 0x30); + err += sn9c102_i2c_write(cam, 0x2f, 0x3d); + err += sn9c102_i2c_write(cam, 0x30, 0x24); + err += sn9c102_i2c_write(cam, 0x32, 0x86); + err += sn9c102_i2c_write(cam, 0x60, 0xa9); + err += sn9c102_i2c_write(cam, 0x61, 0x42); + err += sn9c102_i2c_write(cam, 0x65, 0x00); + err += sn9c102_i2c_write(cam, 0x69, 0x38); + err += sn9c102_i2c_write(cam, 0x6f, 0x88); + err += sn9c102_i2c_write(cam, 0x70, 0x0b); + err += sn9c102_i2c_write(cam, 0x71, 0x00); + err += sn9c102_i2c_write(cam, 0x74, 0x21); + err += sn9c102_i2c_write(cam, 0x7d, 0xf7); break; default: break; @@ -428,9 +425,9 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam) switch (sn9c102_get_bridge(cam)) { case BRIDGE_SN9C101: case BRIDGE_SN9C102: - err += sn9c102_write_reg(cam, 0x01, 0x01); - err += sn9c102_write_reg(cam, 0x00, 0x01); - err += sn9c102_write_reg(cam, 0x28, 0x17); + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); break; case BRIDGE_SN9C103: /* do _not_ change anything! */ err += sn9c102_write_reg(cam, 0x09, 0x01); diff --git a/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c b/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c index d670c24d4..eef90ff3d 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c @@ -22,9 +22,6 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor ov7660; - - static int ov7660_init(struct sn9c102_device* cam) { int err = 0; diff --git a/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c b/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c index 8d79a5fae..a67057210 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c @@ -23,9 +23,6 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor pas106b; - - static int pas106b_init(struct sn9c102_device* cam) { int err = 0; @@ -172,7 +169,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor pas106b = { .name = "PAS106B", .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_2WIRES, diff --git a/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c index 7894f01b5..4447d7cb1 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c @@ -28,9 +28,6 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor pas202bcb; - - static int pas202bcb_init(struct sn9c102_device* cam) { int err = 0; @@ -38,12 +35,12 @@ static int pas202bcb_init(struct sn9c102_device* cam) switch (sn9c102_get_bridge(cam)) { case BRIDGE_SN9C101: case BRIDGE_SN9C102: - err += sn9c102_write_reg(cam, 0x00, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x20, 0x17); - err += sn9c102_write_reg(cam, 0x30, 0x19); - err += sn9c102_write_reg(cam, 0x09, 0x18); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x30, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); break; case BRIDGE_SN9C103: err += sn9c102_write_reg(cam, 0x00, 0x02); diff --git a/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c index 90023ad63..a265767e5 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c @@ -22,9 +22,6 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor tas5110c1b; - - static int tas5110c1b_init(struct sn9c102_device* cam) { int err = 0; @@ -98,7 +95,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor tas5110c1b = { .name = "TAS5110C1B", .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, .sysfs_ops = SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, @@ -146,7 +143,6 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) const struct usb_device_id tas5110c1b_id_table[] = { { USB_DEVICE(0x0c45, 0x6001), }, { USB_DEVICE(0x0c45, 0x6005), }, - { USB_DEVICE(0x0c45, 0x6007), }, { USB_DEVICE(0x0c45, 0x60ab), }, { } }; diff --git a/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c new file mode 100644 index 000000000..4681cfa1b --- /dev/null +++ b/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c @@ -0,0 +1,121 @@ +/*************************************************************************** + * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera * + * Controllers * + * * + * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static int tas5110d_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x04, 0x01); + err += sn9c102_write_reg(cam, 0x0a, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x06, 0x18); + err += sn9c102_write_reg(cam, 0xfb, 0x19); + + err += sn9c102_i2c_write(cam, 0x9a, 0xca); + + return err; +} + + +static int tas5110d_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = sn9c102_get_sensor(cam); + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + err += sn9c102_write_reg(cam, 0x14, 0x1a); + err += sn9c102_write_reg(cam, 0x0a, 0x1b); + + return err; +} + + +static int tas5110d_set_pix_format(struct sn9c102_device* cam, + const struct v4l2_pix_format* pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) + err += sn9c102_write_reg(cam, 0x3b, 0x19); + else + err += sn9c102_write_reg(cam, 0xfb, 0x19); + + return err; +} + + +static struct sn9c102_sensor tas5110d = { + .name = "TAS5110D", + .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, + .sysfs_ops = SN9C102_I2C_WRITE, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x61, + .init = &tas5110d_init, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 352, + .height = 288, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 352, + .height = 288, + }, + }, + .set_crop = &tas5110d_set_crop, + .pix_format = { + .width = 352, + .height = 288, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &tas5110d_set_pix_format +}; + + +int sn9c102_probe_tas5110d(struct sn9c102_device* cam) +{ + const struct usb_device_id tas5110d_id_table[] = { + { USB_DEVICE(0x0c45, 0x6007), }, + { } + }; + + if (!sn9c102_match_id(cam, tas5110d_id_table)) + return -ENODEV; + + sn9c102_attach_sensor(cam, &tas5110d); + + return 0; +} diff --git a/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c index cb1b318bc..a7f711396 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c @@ -22,9 +22,6 @@ #include "sn9c102_sensor.h" -static struct sn9c102_sensor tas5130d1b; - - static int tas5130d1b_init(struct sn9c102_device* cam) { int err = 0; @@ -99,7 +96,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor tas5130d1b = { .name = "TAS5130D1B", .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, .sysfs_ops = SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, |