diff options
Diffstat (limited to 'drivers/media/video')
228 files changed, 6229 insertions, 4850 deletions
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile index 5c7f2f7..bd22223 100644 --- a/drivers/media/video/au0828/Makefile +++ b/drivers/media/video/au0828/Makefile @@ -2,8 +2,8 @@ au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-vid obj-$(CONFIG_VIDEO_AU0828) += au0828.o -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 39fc923..d6adee6 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c @@ -36,6 +36,11 @@ void hvr950q_cs5340_audio(void *priv, int enable) au0828_clear(dev, REG_000, 0x10); } +/* + * WARNING: There's a quirks table at sound/usb/quirks-table.h + * that should also be updated every time a new device with V4L2 support + * is added here. + */ struct au0828_board au0828_boards[] = { [AU0828_BOARD_UNKNOWN] = { .name = "Unknown board", @@ -162,11 +167,14 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) switch (tv.model) { case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */ case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ break; @@ -324,6 +332,10 @@ struct usb_device_id au0828_usb_id_table[] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, { USB_DEVICE(0x2040, 0x8200), .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, + { USB_DEVICE(0x2040, 0x7260), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7213), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { }, }; diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c index ca342e4..1e4ce50 100644 --- a/drivers/media/video/au0828/au0828-core.c +++ b/drivers/media/video/au0828/au0828-core.c @@ -292,3 +292,4 @@ module_exit(au0828_exit); MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.2"); diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 9945aaf..eab0641 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c @@ -33,7 +33,6 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/suspend.h> -#include <linux/version.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-chip-ident.h> @@ -43,8 +42,6 @@ static DEFINE_MUTEX(au0828_sysfs_lock); -#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1) - /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ @@ -1254,8 +1251,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, dev->board.name, sizeof(cap->card)); strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); - cap->version = AU0828_VERSION_CODE; - /*set the device capabilities */ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index e415f6f..3f9a2b2 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -8,6 +8,6 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 3c9e6c7..5939021 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -25,6 +25,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/delay.h> #include <linux/module.h> #include <linux/kmod.h> @@ -2892,13 +2894,10 @@ void __devinit bttv_idcard(struct bttv *btv) { unsigned int gpiobits; int i,type; - unsigned short tmp; /* read PCI subsystem ID */ - pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp); - btv->cardid = tmp << 16; - pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp); - btv->cardid |= tmp; + btv->cardid = btv->c.pci->subsystem_device << 16; + btv->cardid |= btv->c.pci->subsystem_vendor; if (0 != btv->cardid && 0xffffffff != btv->cardid) { /* look for the card */ @@ -2908,19 +2907,17 @@ void __devinit bttv_idcard(struct bttv *btv) if (type != -1) { /* found it */ - printk(KERN_INFO "bttv%d: detected: %s [card=%d], " - "PCI subsystem ID is %04x:%04x\n", - btv->c.nr,cards[type].name,cards[type].cardnr, - btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); + pr_info("%d: detected: %s [card=%d], PCI subsystem ID is %04x:%04x\n", + btv->c.nr, cards[type].name, cards[type].cardnr, + btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); btv->c.type = cards[type].cardnr; } else { /* 404 */ - printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n", - btv->c.nr, btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); - printk(KERN_DEBUG "please mail id, board name and " - "the correct card= insmod option to linux-media@vger.kernel.org\n"); + pr_info("%d: subsystem: %04x:%04x (UNKNOWN)\n", + btv->c.nr, btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); + pr_debug("please mail id, board name and the correct card= insmod option to linux-media@vger.kernel.org\n"); } } @@ -2929,10 +2926,10 @@ void __devinit bttv_idcard(struct bttv *btv) btv->c.type=card[btv->c.nr]; /* print which card config we are using */ - printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr, - bttv_tvcards[btv->c.type].name, btv->c.type, - card[btv->c.nr] < bttv_num_tvcards - ? "insmod option" : "autodetected"); + pr_info("%d: using: %s [card=%d,%s]\n", + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type, + card[btv->c.nr] < bttv_num_tvcards + ? "insmod option" : "autodetected"); /* overwrite gpio stuff ?? */ if (UNSET == audioall && UNSET == audiomux[0]) @@ -2951,12 +2948,13 @@ void __devinit bttv_idcard(struct bttv *btv) } } 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); + pr_info("%d: gpio config override: mask=0x%x, mux=", + btv->c.nr, bttv_tvcards[btv->c.type].gpiomask); for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); + pr_cont("%s0x%x", + i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); } - printk("\n"); + pr_cont("\n"); } /* @@ -2977,8 +2975,8 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) if (-1 != type) { btv->c.type = type; - printk("bttv%d: detected by eeprom: %s [card=%d]\n", - btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); + pr_info("%d: detected by eeprom: %s [card=%d]\n", + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); } } @@ -3022,7 +3020,7 @@ static void flyvideo_gpio(struct bttv *btv) tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ break; default: - printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); + pr_info("%d: FlyVideo_gpio: unknown tuner type\n", btv->c.nr); break; } @@ -3039,13 +3037,13 @@ static void flyvideo_gpio(struct bttv *btv) if (is_capture_only) tuner_type = TUNER_ABSENT; /* No tuner present */ - printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", - btv->c.nr, has_radio ? "yes" : "no ", - has_remote ? "yes" : "no ", tuner_type, gpio); - printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", - btv->c.nr, is_lr90 ? "yes" : "no ", - has_tda9820_tda9821 ? "yes" : "no ", - is_capture_only ? "yes" : "no "); + pr_info("%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", + btv->c.nr, has_radio ? "yes" : "no", + has_remote ? "yes" : "no", tuner_type, gpio); + pr_info("%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", + btv->c.nr, is_lr90 ? "yes" : "no", + has_tda9820_tda9821 ? "yes" : "no", + is_capture_only ? "yes" : "no"); if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ btv->tuner_type = tuner_type; @@ -3094,12 +3092,11 @@ static void miro_pinnacle_gpio(struct bttv *btv) if (btv->c.type == BTTV_BOARD_PINNACLE) btv->c.type = BTTV_BOARD_PINNACLEPRO; } - printk(KERN_INFO - "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", - btv->c.nr, id+1, btv->tuner_type, - !btv->has_radio ? "no" : - (btv->has_matchbox ? "matchbox" : "fmtuner"), - (-1 == msp) ? "no" : "yes"); + pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", + btv->c.nr, id+1, btv->tuner_type, + !btv->has_radio ? "no" : + (btv->has_matchbox ? "matchbox" : "fmtuner"), + (-1 == msp) ? "no" : "yes"); } else { /* new cards with microtune tuner */ id = 63 - id; @@ -3141,9 +3138,8 @@ static void miro_pinnacle_gpio(struct bttv *btv) } if (-1 != msp) btv->c.type = BTTV_BOARD_PINNACLEPRO; - printk(KERN_INFO - "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", - btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); + pr_info("%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", + btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); btv->tuner_type = TUNER_MT2032; } } @@ -3205,7 +3201,7 @@ static void gvc1100_muxsel(struct bttv *btv, unsigned int input) static void init_lmlbt4x(struct bttv *btv) { - printk(KERN_DEBUG "LMLBT4x init\n"); + pr_debug("LMLBT4x init\n"); btwrite(0x000000, BT848_GPIO_REG_INP); gpio_inout(0xffffff, 0x0006C0); gpio_write(0x000000); @@ -3249,7 +3245,7 @@ static void bttv_reset_audio(struct bttv *btv) return; if (bttv_debug) - printk("bttv%d: BT878A ARESET\n",btv->c.nr); + pr_debug("%d: BT878A ARESET\n", btv->c.nr); btwrite((1<<7), 0x058); udelay(10); btwrite( 0, 0x058); @@ -3352,7 +3348,8 @@ void __devinit bttv_init_card2(struct bttv *btv) case BTTV_BOARD_MAGICTVIEW061: if (btv->cardid == 0x3002144f) { btv->has_radio=1; - printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); + pr_info("%d: radio detected by subsystem id (CPH05x)\n", + btv->c.nr); } break; case BTTV_BOARD_STB2: @@ -3441,17 +3438,16 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->tuner_type = tuner[btv->c.nr]; if (btv->tuner_type == TUNER_ABSENT) - printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr); - else if(btv->tuner_type == UNSET) - printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr); + pr_info("%d: tuner absent\n", btv->c.nr); + else if (btv->tuner_type == UNSET) + pr_warn("%d: tuner type unset\n", btv->c.nr); else - printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr, - btv->tuner_type); + pr_info("%d: tuner type=%d\n", btv->c.nr, btv->tuner_type); if (autoload != UNSET) { - printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr); - printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr); - printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr); + pr_warn("%d: the autoload option is obsolete\n", btv->c.nr); + pr_warn("%d: use option msp3400, tda7432 or tvaudio to override which audio module should be used\n", + btv->c.nr); } if (UNSET == btv->tuner_type) @@ -3544,8 +3540,7 @@ void __devinit bttv_init_card2(struct bttv *btv) } default: - printk(KERN_WARNING "bttv%d: unknown audiodev value!\n", - btv->c.nr); + pr_warn("%d: unknown audiodev value!\n", btv->c.nr); return; } @@ -3588,8 +3583,7 @@ void __devinit bttv_init_card2(struct bttv *btv) return; no_audio: - printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n", - btv->c.nr); + pr_warn("%d: audio absent, no audio device found!\n", btv->c.nr); } @@ -3642,19 +3636,19 @@ static void modtec_eeprom(struct bttv *btv) { if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) { btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) { btv->tuner_type=TUNER_PHILIPS_NTSC; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } else { - printk("bttv%d: Modtec: Unknown TunerString: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Unknown TunerString: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } } @@ -3666,7 +3660,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv) btv->tuner_type = tv.tuner_type; btv->has_radio = tv.has_radio; - printk("bttv%d: Hauppauge eeprom indicates model#%d\n", + pr_info("%d: Hauppauge eeprom indicates model#%d\n", btv->c.nr, tv.model); /* @@ -3674,7 +3668,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv) * type based on model #. */ if(tv.model == 64900) { - printk("bttv%d: Switching board type from %s to %s\n", + pr_info("%d: Switching board type from %s to %s\n", btv->c.nr, bttv_tvcards[btv->c.type].name, bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name); @@ -3701,8 +3695,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv) freq=88000/62.5; tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ if (0x1ed8 == tea5757_read(btv)) { - printk("bttv%d: Terratec Active Radio Upgrade found.\n", - btv->c.nr); + pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr); btv->has_radio = 1; btv->has_saa6588 = 1; btv->has_matchbox = 1; @@ -3774,13 +3767,12 @@ static int __devinit pvr_boot(struct bttv *btv) rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev); if (rc != 0) { - printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n", - btv->c.nr); + pr_warn("%d: no altera firmware [via hotplug]\n", btv->c.nr); return rc; } rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size); - printk(KERN_INFO "bttv%d: altera firmware upload %s\n", - btv->c.nr, (rc < 0) ? "failed" : "ok"); + pr_info("%d: altera firmware upload %s\n", + btv->c.nr, (rc < 0) ? "failed" : "ok"); release_firmware(fw_entry); return rc; } @@ -3876,29 +3868,27 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) break; default: /* unknown...leave generic, but get serial # */ - printk(KERN_INFO "bttv%d: " - "osprey eeprom: unknown card type 0x%04x\n", - btv->c.nr, type); + pr_info("%d: osprey eeprom: unknown card type 0x%04x\n", + btv->c.nr, type); break; } serial = get_unaligned_be32((__be32 *)(ee+6)); } - printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n", - btv->c.nr, cardid, - cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial); + pr_info("%d: osprey eeprom: card=%d '%s' serial=%u\n", + btv->c.nr, cardid, + cardid > 0 ? bttv_tvcards[cardid].name : "Unknown", serial); if (cardid<0 || btv->c.type == cardid) return; /* card type isn't set correctly */ if (card[btv->c.nr] < bttv_num_tvcards) { - printk(KERN_WARNING "bttv%d: osprey eeprom: " - "Not overriding user specified card type\n", btv->c.nr); + pr_warn("%d: osprey eeprom: Not overriding user specified card type\n", + btv->c.nr); } else { - printk(KERN_INFO "bttv%d: osprey eeprom: " - "Changing card type from %d to %d\n", btv->c.nr, - btv->c.type, cardid); + pr_info("%d: osprey eeprom: Changing card type from %d to %d\n", + btv->c.nr, btv->c.type, cardid); btv->c.type = cardid; } } @@ -3941,14 +3931,14 @@ static void __devinit avermedia_eeprom(struct bttv *btv) if (tuner_format == 0x09) tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ - printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", + pr_info("%d: Avermedia eeprom[0x%02x%02x]: tuner=", btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); if (tuner_type) { btv->tuner_type = tuner_type; - printk(KERN_CONT "%d", tuner_type); + pr_cont("%d", tuner_type); } else - printk(KERN_CONT "Unknown type"); - printk(KERN_CONT " radio:%s remote control:%s\n", + pr_cont("Unknown type"); + pr_cont(" radio:%s remote control:%s\n", tuner_tv_fm ? "yes" : "no", btv->has_remote ? "yes" : "no"); } @@ -3996,8 +3986,8 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin) if (bttv_gpio) bttv_gpio_tracking(btv,"msp34xx"); if (bttv_verbose) - printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line " - "init [%d]\n", btv->c.nr, pin); + pr_info("%d: Hauppauge/Voodoo msp34xx: reset line init [%d]\n", + btv->c.nr, pin); } /* ----------------------------------------------------------------------- */ @@ -4037,7 +4027,7 @@ static void __devinit init_PXC200(struct bttv *btv) btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); /* Initialise MAX517 DAC */ - printk(KERN_INFO "Setting DAC reference voltage level ...\n"); + pr_info("Setting DAC reference voltage level ...\n"); bttv_I2CWrite(btv,0x5E,0,0x80,1); /* Initialise 12C508 PIC */ @@ -4046,7 +4036,7 @@ static void __devinit init_PXC200(struct bttv *btv) * argument so the numbers are different */ - printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); + pr_info("Initialising 12C508 PIC chip ...\n"); /* First of all, enable the clock line. This is used in the PXC200-F */ val = btread(BT848_GPIO_DMA_CTL); @@ -4065,13 +4055,12 @@ static void __devinit init_PXC200(struct bttv *btv) for (i = 0; i < ARRAY_SIZE(vals); i++) { tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1); if (tmp != -1) { - printk(KERN_INFO - "I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", + pr_info("I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL)); } } - printk(KERN_INFO "PXC200 Initialised.\n"); + pr_info("PXC200 Initialised\n"); } @@ -4110,8 +4099,7 @@ init_RTV24 (struct bttv *btv) uint32_t dataRead = 0; long watchdog_value = 0x0E; - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation in progress ...\n", + pr_info("%d: Adlink RTV-24 initialisation in progress ...\n", btv->c.nr); btwrite (0x00c3feff, BT848_GPIO_OUT_EN); @@ -4125,8 +4113,7 @@ init_RTV24 (struct bttv *btv) dataRead = btread (BT848_GPIO_DATA); if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) { - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", + pr_info("%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", btv->c.nr, dataRead); } @@ -4139,15 +4126,13 @@ init_RTV24 (struct bttv *btv) dataRead = btread (BT848_GPIO_DATA); if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) { - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", + pr_info("%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", btv->c.nr, dataRead); return; } - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr); + pr_info("%d: Adlink RTV-24 initialisation complete\n", btv->c.nr); } @@ -4264,22 +4249,25 @@ static int tea5757_read(struct bttv *btv) while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) schedule(); if (bus_in(btv,btv->mbox_data)) { - printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr); + pr_warn("%d: tea5757: read timeout\n", btv->c.nr); return -1; } - dprintk("bttv%d: tea5757:",btv->c.nr); + dprintk("%d: tea5757:", btv->c.nr); for (i = 0; i < 24; i++) { udelay(5); bus_high(btv,btv->mbox_clk); udelay(5); - dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-'); + dprintk_cont("%c", + bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-'); bus_low(btv,btv->mbox_clk); value <<= 1; value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ - dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M'); + dprintk_cont("%c", + bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M'); } - dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value); + dprintk_cont("\n"); + dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value); return value; } @@ -4298,7 +4286,7 @@ static int tea5757_write(struct bttv *btv, int value) if (bttv_gpio) bttv_gpio_tracking(btv,"tea5757 write"); - dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); + dprintk("%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++) { @@ -4550,7 +4538,7 @@ static void picolo_tetra_init(struct bttv *btv) static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) { - dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel => input = %d\n",btv->c.nr,input); + dprintk("%d : picolo_tetra_muxsel => input = %d\n", btv->c.nr, input); /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/ /*GPIO[20]&GPIO[21] used to choose the right input*/ btwrite (input<<20,BT848_GPIO_DATA); @@ -4595,7 +4583,7 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input) int key = input % 4; int matrix = input / 4; - dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", + dprintk("%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", btv->c.nr, input, matrix, key); /* Handles the input selection on the TDA8540's */ @@ -4652,15 +4640,17 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input) buf[1]=0; rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1); if (rc) { - printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc); + pr_debug("%d: PXC200_muxsel: pic cfg write failed:%d\n", + btv->c.nr, rc); /* not PXC ? do nothing */ - return; + return; } rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); if (!(rc & PX_CFG_PXC200F)) { - printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc); - return; + pr_debug("%d: PXC200_muxsel: not PXC200F rc:%d\n", + btv->c.nr, rc); + return; } @@ -4699,7 +4689,7 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input) else /* older device */ btand(~BT848_IFORM_MUXSEL,BT848_IFORM); - printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux); + pr_debug("%d: setting input channel to:%d\n", btv->c.nr, (int)mux); } static void phytec_muxsel(struct bttv *btv, unsigned int input) @@ -4850,29 +4840,27 @@ void __init bttv_check_chipset(void) /* print warnings about any quirks found */ if (triton1) - printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n"); + pr_info("Host bridge needs ETBF enabled\n"); if (vsfx) - printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); + pr_info("Host bridge needs VSFX enabled\n"); if (pcipci_fail) { - printk(KERN_INFO "bttv: bttv and your chipset may not work " - "together.\n"); + pr_info("bttv and your chipset may not work together\n"); if (!no_overlay) { - printk(KERN_INFO "bttv: overlay will be disabled.\n"); + pr_info("overlay will be disabled\n"); no_overlay = 1; } else { - printk(KERN_INFO "bttv: overlay forced. Use this " - "option at your own risk.\n"); + pr_info("overlay forced. Use this option at your own risk.\n"); } } if (UNSET != latency) - printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency); + pr_info("pci latency fixup [%d]\n", latency); while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev))) { unsigned char b; pci_read_config_byte(dev, 0x53, &b); if (bttv_debug) - printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, " - "bufcon=0x%02x\n",b); + pr_info("Host bridge: 82441FX Natoma, bufcon=0x%02x\n", + b); } } @@ -4885,12 +4873,13 @@ int __devinit bttv_handle_chipset(struct bttv *btv) if (bttv_verbose) { if (triton1) - printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr); + pr_info("%d: enabling ETBF (430FX/VP3 compatibility)\n", + btv->c.nr); if (vsfx && btv->id >= 878) - printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr); + pr_info("%d: enabling VSFX\n", btv->c.nr); if (UNSET != latency) - printk(KERN_INFO "bttv%d: setting pci timer to %d\n", - btv->c.nr,latency); + pr_info("%d: setting pci timer to %d\n", + btv->c.nr, latency); } if (btv->id < 878) { diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 834a483..3dd0660 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -34,6 +34,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> @@ -57,6 +59,7 @@ #include <media/saa6588.h> +#define BTTV_VERSION "0.9.19" unsigned int bttv_num; /* number of Bt848s in use */ struct bttv *bttvs[BTTV_MAX]; @@ -163,6 +166,7 @@ MODULE_PARM_DESC(radio_nr, "radio device numbers"); MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); MODULE_LICENSE("GPL"); +MODULE_VERSION(BTTV_VERSION); /* ----------------------------------------------------------------------- */ /* sysfs */ @@ -940,8 +944,8 @@ static void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) { if ((fh->resources & bits) != bits) { - /* trying to free ressources not allocated by us ... */ - printk("bttv: BUG! (btres)\n"); + /* trying to free resources not allocated by us ... */ + pr_err("BUG! (btres)\n"); } fh->resources &= ~bits; btv->resources &= ~bits; @@ -998,7 +1002,7 @@ static void set_pll(struct bttv *btv) return; if (btv->pll.pll_ofreq == btv->pll.pll_current) { - dprintk("bttv%d: PLL: no change required\n",btv->c.nr); + dprintk("%d: PLL: no change required\n", btv->c.nr); return; } @@ -1006,21 +1010,23 @@ static void set_pll(struct bttv *btv) /* no PLL needed */ if (btv->pll.pll_current == 0) return; - bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n", - btv->c.nr,btv->pll.pll_ifreq); + if (bttv_verbose) + pr_info("%d: PLL can sleep, using XTAL (%d)\n", + btv->c.nr, btv->pll.pll_ifreq); btwrite(0x00,BT848_TGCTRL); btwrite(0x00,BT848_PLL_XCI); btv->pll.pll_current = 0; return; } - bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); + if (bttv_verbose) + pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n", + btv->c.nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); for (i=0; i<10; i++) { /* Let other people run while the PLL stabilizes */ - bttv_printk("."); msleep(10); if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { @@ -1028,12 +1034,14 @@ static void set_pll(struct bttv *btv) } else { btwrite(0x08,BT848_TGCTRL); btv->pll.pll_current = btv->pll.pll_ofreq; - bttv_printk(" ok\n"); + if (bttv_verbose) + pr_info("PLL set ok\n"); return; } } btv->pll.pll_current = -1; - bttv_printk("failed\n"); + if (bttv_verbose) + pr_info("Setting PLL failed\n"); return; } @@ -1045,7 +1053,7 @@ static void bt848A_set_timing(struct bttv *btv) int fsc = bttv_tvnorms[btv->tvnorm].Fsc; if (btv->input == btv->dig) { - dprintk("bttv%d: load digital timing table (table_idx=%d)\n", + dprintk("%d: load digital timing table (table_idx=%d)\n", btv->c.nr,table_idx); /* timing change...reset timing generator address */ @@ -1074,7 +1082,7 @@ static void bt848_bright(struct bttv *btv, int bright) { int value; - // printk("bttv: set bright: %d\n",bright); // DEBUG + // printk("set bright: %d\n", bright); // DEBUG btv->bright = bright; /* We want -128 to 127 we get 0-65535 */ @@ -1148,8 +1156,7 @@ video_mux(struct bttv *btv, unsigned int input) } mux = bttv_muxsel(btv, input); btaor(mux<<5, ~(3<<5), BT848_IFORM); - dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n", - btv->c.nr,input,mux); + dprintk("%d: video mux: input=%d mux=%d\n", btv->c.nr, input, mux); /* card specific hook */ if(bttv_tvcards[btv->c.type].muxsel_hook) @@ -1438,7 +1445,7 @@ static void bttv_reinit_bt848(struct bttv *btv) unsigned long flags; if (bttv_verbose) - printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr); + pr_info("%d: reset, reinitialize\n", btv->c.nr); spin_lock_irqsave(&btv->s_lock,flags); btv->errors=0; bttv_set_dma(btv,0); @@ -1620,8 +1627,8 @@ void bttv_gpio_tracking(struct bttv *btv, char *comment) unsigned int outbits, data; outbits = btread(BT848_GPIO_OUT_EN); data = btread(BT848_GPIO_DATA); - printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", - btv->c.nr,outbits,data & outbits, data & ~outbits, comment); + pr_debug("%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", + btv->c.nr, outbits, data & outbits, data & ~outbits, comment); } static void bttv_field_count(struct bttv *btv) @@ -1666,7 +1673,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, unsigned long flags; int retval = 0; - dprintk("switch_overlay: enter [new=%p]\n",new); + dprintk("switch_overlay: enter [new=%p]\n", new); if (new) new->vb.state = VIDEOBUF_DONE; spin_lock_irqsave(&btv->s_lock,flags); @@ -1676,7 +1683,8 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, bttv_set_dma(btv, 0x03); spin_unlock_irqrestore(&btv->s_lock,flags); if (NULL != old) { - dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state); + dprintk("switch_overlay: old=%p state is %d\n", + old, old->vb.state); bttv_dma_free(&fh->cap,btv, old); kfree(old); } @@ -2027,11 +2035,11 @@ static int bttv_log_status(struct file *file, void *f) struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); + pr_info("%d: ======== START STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); bttv_call_all(btv, core, log_status); - printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); + pr_info("%d: ======== END STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); return 0; } @@ -2596,7 +2604,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, struct bttv *btv = fh->btv; if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -2616,7 +2624,6 @@ static int bttv_querycap(struct file *file, void *priv, strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | @@ -2672,7 +2679,7 @@ static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv, int rc; if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -2713,7 +2720,7 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) return -EINVAL; } if (unlikely(!fh->ov.setup_ok)) { - dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr); + dprintk("%d: overlay: !setup_ok\n", btv->c.nr); retval = -EINVAL; } if (retval) @@ -3090,8 +3097,8 @@ static ssize_t bttv_read(struct file *file, char __user *data, if (fh->btv->errors) bttv_reinit_bt848(fh->btv); - dprintk("bttv%d: read count=%d type=%s\n", - fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]); + dprintk("%d: read count=%d type=%s\n", + fh->btv->c.nr, (int)count, v4l2_type_names[fh->type]); switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -3173,7 +3180,7 @@ static int bttv_open(struct file *file) struct bttv_fh *fh; enum v4l2_buf_type type = 0; - dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev)); + dprintk("open dev=%s\n", video_device_node_name(vdev)); if (vdev->vfl_type == VFL_TYPE_GRABBER) { type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -3184,8 +3191,8 @@ static int bttv_open(struct file *file) return -ENODEV; } - dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", - btv->c.nr,v4l2_type_names[type]); + dprintk("%d: open called (type=%s)\n", + btv->c.nr, v4l2_type_names[type]); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh), GFP_KERNEL); @@ -3287,7 +3294,7 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma) { struct bttv_fh *fh = file->private_data; - dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n", + dprintk("%d: mmap type=%s 0x%lx+%ld\n", fh->btv->c.nr, v4l2_type_names[fh->type], vma->vm_start, vma->vm_end - vma->vm_start); return videobuf_mmap_mapper(bttv_queue(fh),vma); @@ -3369,9 +3376,9 @@ static int radio_open(struct file *file) struct bttv *btv = video_drvdata(file); struct bttv_fh *fh; - dprintk("bttv: open dev=%s\n", video_device_node_name(vdev)); + dprintk("open dev=%s\n", video_device_node_name(vdev)); - dprintk("bttv%d: open called (radio)\n",btv->c.nr); + dprintk("%d: open called (radio)\n", btv->c.nr); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh), GFP_KERNEL); @@ -3416,7 +3423,6 @@ static int radio_querycap(struct file *file, void *priv, strcpy(cap->driver, "bttv"); strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; @@ -3616,12 +3622,12 @@ static int bttv_risc_decode(u32 risc) }; int i; - printk("0x%08x [ %s", risc, + pr_cont("0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); - printk(" count=%d ]\n", risc & 0xfff); + pr_cont(" %s", bits[i]); + pr_cont(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } @@ -3630,16 +3636,18 @@ static void bttv_risc_disasm(struct bttv *btv, { unsigned int i,j,n; - printk("%s: risc disasm: %p [dma=0x%08lx]\n", - btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); + pr_info("%s: risc disasm: %p [dma=0x%08lx]\n", + btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); for (i = 0; i < (risc->size >> 2); i += n) { - printk("%s: 0x%lx: ", btv->c.v4l2_dev.name, - (unsigned long)(risc->dma + (i<<2))); + pr_info("%s: 0x%lx: ", + btv->c.v4l2_dev.name, + (unsigned long)(risc->dma + (i<<2))); n = bttv_risc_decode(le32_to_cpu(risc->cpu[i])); for (j = 1; j < n; j++) - printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n", - btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)), - risc->cpu[i+j], j); + pr_info("%s: 0x%lx: 0x%08x [ arg #%d ]\n", + btv->c.v4l2_dev.name, + (unsigned long)(risc->dma + ((i+j)<<2)), + risc->cpu[i+j], j); if (0 == risc->cpu[i]) break; } @@ -3647,17 +3655,18 @@ static void bttv_risc_disasm(struct bttv *btv, static void bttv_print_riscaddr(struct bttv *btv) { - printk(" main: %08Lx\n", - (unsigned long long)btv->main.dma); - printk(" vbi : o=%08Lx e=%08Lx\n", - btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, - btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); - printk(" cap : o=%08Lx e=%08Lx\n", - btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, - btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); - printk(" scr : o=%08Lx e=%08Lx\n", - btv->screen ? (unsigned long long)btv->screen->top.dma : 0, - btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); + pr_info(" main: %08llx\n", (unsigned long long)btv->main.dma); + pr_info(" vbi : o=%08llx e=%08llx\n", + btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, + btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); + pr_info(" cap : o=%08llx e=%08llx\n", + btv->curr.top + ? (unsigned long long)btv->curr.top->top.dma : 0, + btv->curr.bottom + ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); + pr_info(" scr : o=%08llx e=%08llx\n", + btv->screen ? (unsigned long long)btv->screen->top.dma : 0, + btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); bttv_risc_disasm(btv, &btv->main); } @@ -3690,34 +3699,34 @@ static void bttv_print_irqbits(u32 print, u32 mark) { unsigned int i; - printk("bits:"); + pr_cont("bits:"); for (i = 0; i < ARRAY_SIZE(irq_name); i++) { if (print & (1 << i)) - printk(" %s",irq_name[i]); + pr_cont(" %s", irq_name[i]); if (mark & (1 << i)) - printk("*"); + pr_cont("*"); } } static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) { - printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", - btv->c.nr, - (unsigned long)btv->main.dma, - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), - (unsigned long)rc); + pr_warn("%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", + btv->c.nr, + (unsigned long)btv->main.dma, + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), + (unsigned long)rc); if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { - printk("bttv%d: Oh, there (temporarely?) is no input signal. " - "Ok, then this is harmless, don't worry ;)\n", - btv->c.nr); + pr_notice("%d: Oh, there (temporarily?) is no input signal. " + "Ok, then this is harmless, don't worry ;)\n", + btv->c.nr); return; } - printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n", - btv->c.nr); - printk("bttv%d: Lets try to catch the culpit red-handed ...\n", - btv->c.nr); + pr_notice("%d: Uhm. Looks like we have unusual high IRQ latencies\n", + btv->c.nr); + pr_notice("%d: Lets try to catch the culpit red-handed ...\n", + btv->c.nr); dump_stack(); } @@ -3798,9 +3807,9 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) } } - dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", - btv->c.nr,set->top, set->bottom, - btv->screen,set->frame_irq,set->top_irq); + dprintk("%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", + btv->c.nr, set->top, set->bottom, + btv->screen, set->frame_irq, set->top_irq); return 0; } @@ -3815,7 +3824,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, if (wakeup->top == wakeup->bottom) { if (NULL != wakeup->top && curr->top != wakeup->top) { if (irq_debug > 1) - printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top); + pr_debug("%d: wakeup: both=%p\n", + btv->c.nr, wakeup->top); wakeup->top->vb.ts = ts; wakeup->top->vb.field_count = btv->field_count; wakeup->top->vb.state = state; @@ -3824,7 +3834,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, } else { if (NULL != wakeup->top && curr->top != wakeup->top) { if (irq_debug > 1) - printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top); + pr_debug("%d: wakeup: top=%p\n", + btv->c.nr, wakeup->top); wakeup->top->vb.ts = ts; wakeup->top->vb.field_count = btv->field_count; wakeup->top->vb.state = state; @@ -3832,7 +3843,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, } if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) { if (irq_debug > 1) - printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom); + pr_debug("%d: wakeup: bottom=%p\n", + btv->c.nr, wakeup->bottom); wakeup->bottom->vb.ts = ts; wakeup->bottom->vb.field_count = btv->field_count; wakeup->bottom->vb.state = state; @@ -3866,11 +3878,11 @@ static void bttv_irq_timeout(unsigned long data) unsigned long flags; if (bttv_verbose) { - printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", - btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, - btread(BT848_RISC_COUNT)); + pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", + btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, + btread(BT848_RISC_COUNT)); bttv_print_irqbits(btread(BT848_INT_STAT),0); - printk("\n"); + pr_cont("\n"); } spin_lock_irqsave(&btv->s_lock,flags); @@ -4033,21 +4045,23 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) dstat=btread(BT848_DSTATUS); if (irq_debug) { - printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d " - "riscs=%x, riscc=%08x, ", - btv->c.nr, count, btv->field_count, - stat>>28, btread(BT848_RISC_COUNT)); + pr_debug("%d: irq loop=%d fc=%d riscs=%x, riscc=%08x, ", + btv->c.nr, count, btv->field_count, + stat>>28, btread(BT848_RISC_COUNT)); bttv_print_irqbits(stat,astat); if (stat & BT848_INT_HLOCK) - printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC) - ? "yes" : "no"); + pr_cont(" HLOC => %s", + dstat & BT848_DSTATUS_HLOC + ? "yes" : "no"); if (stat & BT848_INT_VPRES) - printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES) - ? "yes" : "no"); + pr_cont(" PRES => %s", + dstat & BT848_DSTATUS_PRES + ? "yes" : "no"); if (stat & BT848_INT_FMTCHG) - printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML) - ? "625" : "525"); - printk("\n"); + pr_cont(" NUML => %s", + dstat & BT848_DSTATUS_NUML + ? "625" : "525"); + pr_cont("\n"); } if (astat&BT848_INT_VSYNC) @@ -4075,18 +4089,19 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) audio_mute(btv, btv->mute); /* trigger automute */ if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { - printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr, - (astat & BT848_INT_SCERR) ? "SCERR" : "", - (astat & BT848_INT_OCERR) ? "OCERR" : "", - btread(BT848_RISC_COUNT)); + pr_info("%d: %s%s @ %08x,", + btv->c.nr, + (astat & BT848_INT_SCERR) ? "SCERR" : "", + (astat & BT848_INT_OCERR) ? "OCERR" : "", + btread(BT848_RISC_COUNT)); bttv_print_irqbits(stat,astat); - printk("\n"); + pr_cont("\n"); if (bttv_debug) bttv_print_riscaddr(btv); } if (fdsr && astat & BT848_INT_FDSR) { - printk(KERN_INFO "bttv%d: FDSR @ %08x\n", - btv->c.nr,btread(BT848_RISC_COUNT)); + pr_info("%d: FDSR @ %08x\n", + btv->c.nr, btread(BT848_RISC_COUNT)); if (bttv_debug) bttv_print_riscaddr(btv); } @@ -4097,11 +4112,11 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) if (count > 8 || !(astat & BT848_INT_GPINT)) { btwrite(0, BT848_INT_MASK); - printk(KERN_ERR - "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr); + pr_err("%d: IRQ lockup, cleared int mask [", + btv->c.nr); } else { - printk(KERN_ERR - "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr); + pr_err("%d: IRQ lockup, clearing GPINT from int mask [", + btv->c.nr); btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), BT848_INT_MASK); @@ -4109,7 +4124,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) bttv_print_irqbits(stat,astat); - printk("]\n"); + pr_cont("]\n"); } } btv->irq_total++; @@ -4171,7 +4186,7 @@ static void bttv_unregister_video(struct bttv *btv) static int __devinit bttv_register_video(struct bttv *btv) { if (no_overlay > 0) - printk("bttv: Overlay support disabled.\n"); + pr_notice("Overlay support disabled\n"); /* video */ btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); @@ -4181,12 +4196,11 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, video_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->video_dev)); + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->video_dev)); if (device_create_file(&btv->video_dev->dev, &dev_attr_card)<0) { - printk(KERN_ERR "bttv%d: device_create_file 'card' " - "failed\n", btv->c.nr); + pr_err("%d: device_create_file 'card' failed\n", btv->c.nr); goto err; } @@ -4198,8 +4212,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, vbi_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->vbi_dev)); + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->vbi_dev)); if (!btv->has_radio) return 0; @@ -4210,8 +4224,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->radio_dev)); + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->radio_dev)); /* all done */ return 0; @@ -4244,10 +4258,10 @@ static int __devinit bttv_probe(struct pci_dev *dev, if (bttv_num == BTTV_MAX) return -ENOMEM; - printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); + pr_info("Bt8xx card found (%d)\n", bttv_num); bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL); if (btv == NULL) { - printk(KERN_ERR "bttv: out of memory.\n"); + pr_err("out of memory\n"); return -ENOMEM; } btv->c.nr = bttv_num; @@ -4277,21 +4291,19 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->c.pci = dev; btv->id = dev->device; if (pci_enable_device(dev)) { - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); + pr_warn("%d: Can't enable device\n", btv->c.nr); return -EIO; } if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", - btv->c.nr); + pr_warn("%d: No suitable DMA available\n", btv->c.nr); return -EIO; } if (!request_mem_region(pci_resource_start(dev,0), pci_resource_len(dev,0), btv->c.v4l2_dev.name)) { - printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n", - btv->c.nr, - (unsigned long long)pci_resource_start(dev,0)); + pr_warn("%d: can't request iomem (0x%llx)\n", + btv->c.nr, + (unsigned long long)pci_resource_start(dev, 0)); return -EBUSY; } pci_set_master(dev); @@ -4299,22 +4311,21 @@ static int __devinit bttv_probe(struct pci_dev *dev, result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev); if (result < 0) { - printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr); + pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr); goto fail0; } btv->revision = dev->revision; pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", - bttv_num,btv->id, btv->revision, pci_name(dev)); - printk("irq: %d, latency: %d, mmio: 0x%llx\n", - btv->c.pci->irq, lat, - (unsigned long long)pci_resource_start(dev,0)); + pr_info("%d: Bt%d (rev %d) at %s, irq: %d, latency: %d, mmio: 0x%llx\n", + bttv_num, btv->id, btv->revision, pci_name(dev), + btv->c.pci->irq, lat, + (unsigned long long)pci_resource_start(dev, 0)); schedule(); btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000); if (NULL == btv->bt848_mmio) { - printk("bttv%d: ioremap() failed\n", btv->c.nr); + pr_err("%d: ioremap() failed\n", btv->c.nr); result = -EIO; goto fail1; } @@ -4327,8 +4338,8 @@ static int __devinit bttv_probe(struct pci_dev *dev, result = request_irq(btv->c.pci->irq, bttv_irq, IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv); if (result < 0) { - printk(KERN_ERR "bttv%d: can't get IRQ %d\n", - bttv_num,btv->c.pci->irq); + pr_err("%d: can't get IRQ %d\n", + bttv_num, btv->c.pci->irq); goto fail1; } @@ -4433,7 +4444,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev) struct bttv *btv = to_bttv(v4l2_dev); if (bttv_verbose) - printk("bttv%d: unloading\n",btv->c.nr); + pr_info("%d: unloading\n", btv->c.nr); if (bttv_tvcards[btv->c.type].has_dvb) flush_request_modules(btv); @@ -4481,7 +4492,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) struct bttv_buffer_set idle; unsigned long flags; - dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event); + dprintk("%d: suspend %d\n", btv->c.nr, state.event); /* stop dma + irqs */ spin_lock_irqsave(&btv->s_lock,flags); @@ -4517,14 +4528,13 @@ static int bttv_resume(struct pci_dev *pci_dev) unsigned long flags; int err; - dprintk("bttv%d: resume\n", btv->c.nr); + dprintk("%d: resume\n", btv->c.nr); /* restore pci state */ if (btv->state.disabled) { err=pci_enable_device(pci_dev); if (err) { - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); + pr_warn("%d: Can't enable device\n", btv->c.nr); return err; } btv->state.disabled = 0; @@ -4532,8 +4542,7 @@ static int bttv_resume(struct pci_dev *pci_dev) err=pci_set_power_state(pci_dev, PCI_D0); if (err) { pci_disable_device(pci_dev); - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); + pr_warn("%d: Can't enable device\n", btv->c.nr); btv->state.disabled = 1; return err; } @@ -4585,28 +4594,21 @@ static int __init bttv_init_module(void) bttv_num = 0; - printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", - (BTTV_VERSION_CODE >> 16) & 0xff, - (BTTV_VERSION_CODE >> 8) & 0xff, - BTTV_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + pr_info("driver version %s loaded\n", BTTV_VERSION); if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) gbuffers = 2; if (gbufsize > BTTV_MAX_FBUF) gbufsize = BTTV_MAX_FBUF; gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; if (bttv_verbose) - printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n", - gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); + pr_info("using %d buffers with %dk (%d pages) each for capture\n", + gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); bttv_check_chipset(); ret = bus_register(&bttv_sub_bus_type); if (ret < 0) { - printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); + pr_warn("bus_register error: %d\n", ret); return ret; } ret = pci_register_driver(&bttv_pci_driver); diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index 13ce72c..922e823 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c @@ -26,6 +26,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> @@ -99,7 +101,7 @@ int bttv_sub_add_device(struct bttv_core *core, char *name) kfree(sub); return err; } - printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); + pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); list_add_tail(&sub->list,&core->subs); return 0; } diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index d49b675..e3952af 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -27,6 +27,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> @@ -154,9 +156,7 @@ bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) if (retval == 0) goto eio; if (i2c_debug) { - printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); + pr_cont(" <W %02x %02x", msg->addr << 1, msg->buf[0]); } for (cnt = 1; cnt < msg->len; cnt++ ) { @@ -170,19 +170,18 @@ bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) goto err; if (retval == 0) goto eio; - if (i2c_debug) { - printk(" %02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } + if (i2c_debug) + pr_cont(" %02x", msg->buf[cnt]); } + if (!(xmit & BT878_I2C_NOSTOP)) + pr_cont(">\n"); return msg->len; eio: retval = -EIO; err: if (i2c_debug) - printk(" ERR: %d\n",retval); + pr_cont(" ERR: %d\n",retval); return retval; } @@ -193,7 +192,7 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) u32 cnt; int retval; - for(cnt = 0; cnt < msg->len; cnt++) { + for (cnt = 0; cnt < msg->len; cnt++) { xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; if (cnt < msg->len-1) xmit |= BT848_I2C_W3B; @@ -201,6 +200,12 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) xmit |= BT878_I2C_NOSTOP; if (cnt) xmit |= BT878_I2C_NOSTART; + + if (i2c_debug) { + if (!(xmit & BT878_I2C_NOSTART)) + pr_cont(" <R %02x", (msg->addr << 1) +1); + } + btwrite(xmit, BT848_I2C); retval = bttv_i2c_wait_done(btv); if (retval < 0) @@ -209,20 +214,20 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) goto eio; msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; if (i2c_debug) { - if (!(xmit & BT878_I2C_NOSTART)) - printk(" <R %02x", (msg->addr << 1) +1); - printk(" =%02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); + pr_cont(" =%02x", msg->buf[cnt]); } + if (i2c_debug && !(xmit & BT878_I2C_NOSTOP)) + pr_cont(" >\n"); } + + return msg->len; eio: retval = -EIO; err: if (i2c_debug) - printk(" ERR: %d\n",retval); + pr_cont(" ERR: %d\n",retval); return retval; } @@ -234,7 +239,8 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int int i; if (i2c_debug) - printk("bt-i2c:"); + pr_debug("bt-i2c:"); + btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); for (i = 0 ; i < num; i++) { if (msgs[i].flags & I2C_M_RD) { @@ -271,20 +277,20 @@ int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) if (0 != btv->i2c_rc) return -1; if (bttv_verbose && NULL != probe_for) - printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", - btv->c.nr,probe_for,addr); + pr_info("%d: i2c: checking for %s @ 0x%02x... ", + btv->c.nr, probe_for, addr); btv->i2c_client.addr = addr >> 1; if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { if (NULL != probe_for) { if (bttv_verbose) - printk("not found\n"); + pr_cont("not found\n"); } else - printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", - btv->c.nr,addr); + pr_warn("%d: i2c read 0x%x: error\n", + btv->c.nr, addr); return -1; } if (bttv_verbose && NULL != probe_for) - printk("found\n"); + pr_cont("found\n"); return buffer; } @@ -335,8 +341,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c,&buf,0); if (rc < 0) continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + pr_info("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 677d70c..ef4c7cd 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> @@ -36,9 +38,10 @@ static int ir_rc5_remote_gap = 885; module_param(ir_rc5_remote_gap, int, 0644); #undef dprintk -#define dprintk(arg...) do { \ - if (ir_debug >= 1) \ - printk(arg); \ +#define dprintk(fmt, ...) \ +do { \ + if (ir_debug >= 1) \ + pr_info(fmt, ##__VA_ARGS__); \ } while (0) #define DEVNAME "bttv-input" @@ -62,7 +65,7 @@ static void ir_handle_key(struct bttv *btv) /* extract data */ data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", + dprintk("irq gpio=0x%x code=%d | %s%s%s\n", gpio, data, ir->polling ? "poll" : "irq", (gpio & ir->mask_keydown) ? " down" : "", @@ -96,7 +99,7 @@ static void ir_enltv_handle_key(struct bttv *btv) keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; if ((ir->last_gpio & 0x7f) != data) { - dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n", + dprintk("gpio=0x%x code=%d | %s\n", gpio, data, (gpio & ir->mask_keyup) ? " up" : "up/down"); @@ -107,7 +110,7 @@ static void ir_enltv_handle_key(struct bttv *btv) if ((ir->last_gpio & 1 << 31) == keyup) return; - dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n", + dprintk("(cnt) gpio=0x%x code=%d | %s\n", gpio, data, (gpio & ir->mask_keyup) ? " up" : "down"); @@ -177,13 +180,12 @@ static u32 bttv_rc5_decode(unsigned int code) rc5 |= 1; break; case 3: - dprintk(KERN_INFO DEVNAME ":rc5_decode(%x) bad code\n", + dprintk("rc5_decode(%x) bad code\n", org_code); return 0; } } - dprintk(KERN_INFO DEVNAME ":" - "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " + dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " "instr=%x\n", rc5, org_code, RC5_START(rc5), RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); return rc5; @@ -212,20 +214,20 @@ static void bttv_rc5_timer_end(unsigned long data) /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ if (gap < 28000) { - dprintk(KERN_INFO DEVNAME ": spurious timer_end\n"); + dprintk("spurious timer_end\n"); return; } if (ir->last_bit < 20) { /* ignore spurious codes (caused by light/other remotes) */ - dprintk(KERN_INFO DEVNAME ": short code: %x\n", ir->code); + dprintk("short code: %x\n", ir->code); } else { ir->code = (ir->code << ir->shift_by) | 1; rc5 = bttv_rc5_decode(ir->code); /* two start bits? */ if (RC5_START(rc5) != ir->start) { - printk(KERN_INFO DEVNAME ":" + pr_info(DEVNAME ":" " rc5 start bits invalid: %u\n", RC5_START(rc5)); /* right address? */ @@ -235,8 +237,7 @@ static void bttv_rc5_timer_end(unsigned long data) /* Good code */ rc_keydown(ir->dev, instr, toggle); - dprintk(KERN_INFO DEVNAME ":" - " instruction %x, toggle %x\n", + dprintk("instruction %x, toggle %x\n", instr, toggle); } } @@ -265,7 +266,7 @@ static int bttv_rc5_irq(struct bttv *btv) tv.tv_usec - ir->base_time.tv_usec; } - dprintk(KERN_INFO DEVNAME ": RC5 IRQ: gap %d us for %s\n", + dprintk("RC5 IRQ: gap %d us for %s\n", gap, (gpio & 0x20) ? "mark" : "space"); /* remote IRQ? */ @@ -340,14 +341,14 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(KERN_INFO DEVNAME ": read error\n"); + dprintk("read error\n"); return -EIO; } /* ignore 0xaa */ if (b==0xaa) return 0; - dprintk(KERN_INFO DEVNAME ": key %02x\n", b); + dprintk("key %02x\n", b); /* * NOTE: @@ -517,7 +518,7 @@ int bttv_input_init(struct bttv *btv) break; } if (NULL == ir_codes) { - dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type); + dprintk("Ooops: IR config error [card=%d]\n", btv->c.type); err = -ENODEV; goto err_out_free; } diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 9b57d09..82cc47d 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -24,6 +24,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -473,8 +475,7 @@ bttv_set_dma(struct bttv *btv, int override) capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ capctl |= override; - d2printk(KERN_DEBUG - "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", + d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n", btv->c.nr,capctl,btv->loop_irq, btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, @@ -517,8 +518,8 @@ bttv_risc_init_main(struct bttv *btv) if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) return rc; - dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n", - btv->c.nr,(unsigned long long)btv->main.dma); + dprintk("%d: risc main @ %08llx\n", + btv->c.nr, (unsigned long long)btv->main.dma); btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | BT848_FIFO_STATUS_VRE); @@ -557,12 +558,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, unsigned long next = btv->main.dma + ((slot+2) << 2); if (NULL == risc) { - d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n", - btv->c.nr,risc,slot); + d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot); btv->main.cpu[slot+1] = cpu_to_le32(next); } else { - d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n", - btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags); + d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n", + btv->c.nr, risc, slot, + (unsigned long long)risc->dma, irqflags); cmd = BT848_RISC_JUMP; if (irqflags) { cmd |= BT848_RISC_IRQ; @@ -708,8 +709,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - dprintk(KERN_DEBUG - "bttv%d: buffer field: %s format: %s size: %dx%d\n", + dprintk("%d: buffer field: %s format: %s size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], buf->fmt->name, buf->vb.width, buf->vb.height); @@ -870,10 +870,9 @@ bttv_overlay_risc(struct bttv *btv, struct bttv_buffer *buf) { /* check interleave, bottom+top fields */ - dprintk(KERN_DEBUG - "bttv%d: overlay fields: %s format: %s size: %dx%d\n", + dprintk("%d: overlay fields: %s format: %s size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], - fmt->name,ov->w.width,ov->w.height); + fmt->name, ov->w.width, ov->w.height); /* calculate geometry */ bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index e79a402..b433267 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -23,6 +23,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> @@ -65,8 +67,11 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)"); #ifdef dprintk # undef dprintk #endif -#define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg) +#define dprintk(fmt, ...) \ +do { \ + if (vbi_debug) \ + pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__); \ +} while (0) #define IMAGE_SIZE(fmt) \ (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line) diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 9b776fa..db943a8d 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -25,9 +25,6 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#include <linux/version.h> -#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18) - #include <linux/types.h> #include <linux/wait.h> #include <linux/i2c.h> @@ -313,9 +310,21 @@ extern unsigned int bttv_gpio; extern void bttv_gpio_tracking(struct bttv *btv, char *comment); extern int init_bttv_i2c(struct bttv *btv); -#define bttv_printk if (bttv_verbose) printk -#define dprintk if (bttv_debug >= 1) printk -#define d2printk if (bttv_debug >= 2) printk +#define dprintk(fmt, ...) \ +do { \ + if (bttv_debug >= 1) \ + pr_debug(fmt, ##__VA_ARGS__); \ +} while (0) +#define dprintk_cont(fmt, ...) \ +do { \ + if (bttv_debug >= 1) \ + pr_cont(fmt, ##__VA_ARGS__); \ +} while (0) +#define d2printk(fmt, ...) \ +do { \ + if (bttv_debug >= 2) \ + printk(fmt, ##__VA_ARGS__); \ +} while (0) #define BTTV_MAX_FBUF 0x208000 #define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h index 6d6d184..ab25218 100644 --- a/drivers/media/video/cpia2/cpia2.h +++ b/drivers/media/video/cpia2/cpia2.h @@ -31,7 +31,6 @@ #ifndef __CPIA2_H__ #define __CPIA2_H__ -#include <linux/version.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <linux/usb.h> @@ -43,10 +42,6 @@ /* define for verbose debug output */ //#define _CPIA2_DEBUG_ -#define CPIA2_MAJ_VER 3 -#define CPIA2_MIN_VER 0 -#define CPIA2_PATCH_VER 0 - /*** * Image defines ***/ diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c index dc5b07a..59c797c 100644 --- a/drivers/media/video/cpia2/cpia2_usb.c +++ b/drivers/media/video/cpia2/cpia2_usb.c @@ -31,6 +31,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/module.h> #include "cpia2.h" diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 40eb632..077eb1d 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -29,8 +29,7 @@ * Alan Cox <alan@lxorguk.ukuu.org.uk> ****************************************************************************/ -#include <linux/version.h> - +#define CPIA_VERSION "3.0.1" #include <linux/module.h> #include <linux/time.h> @@ -80,6 +79,7 @@ MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); MODULE_SUPPORTED_DEVICE("video"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CPIA_VERSION); #define ABOUT "V4L-Driver for Vision CPiA2 based cameras" @@ -465,9 +465,6 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) memset(vc->bus_info,0, sizeof(vc->bus_info)); - vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, - CPIA2_PATCH_VER); - vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; @@ -1558,8 +1555,8 @@ static void __init check_parameters(void) *****************************************************************************/ static int __init cpia2_init(void) { - LOG("%s v%d.%d.%d\n", - ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); + LOG("%s v%s\n", + ABOUT, CPIA_VERSION); check_parameters(); cpia2_usb_init(); return 0; @@ -1579,4 +1576,3 @@ static void __exit cpia2_exit(void) module_init(cpia2_init); module_exit(cpia2_exit); - diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile index 2fadd9d..a86bab5 100644 --- a/drivers/media/video/cx18/Makefile +++ b/drivers/media/video/cx18/Makefile @@ -8,6 +8,6 @@ cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o obj-$(CONFIG_VIDEO_CX18) += cx18.o obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c index d50d69d..a1e6c2a 100644 --- a/drivers/media/video/cx18/cx18-alsa-main.c +++ b/drivers/media/video/cx18/cx18-alsa-main.c @@ -192,6 +192,7 @@ static int snd_cx18_init(struct v4l2_device *v4l2_dev) err_exit_free: if (sc != NULL) snd_card_free(sc); + kfree(cxsc); err_exit: return ret; } diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 9e2f870..c6ff32a 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -1085,6 +1085,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, setup.addr = ADDR_UNSET; setup.type = cx->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + if (cx->options.radio > 0) + setup.mode_mask |= T_RADIO; setup.tuner_callback = (setup.type == TUNER_XC2028) ? cx18_reset_tuner_gpio : NULL; cx18_call_all(cx, tuner, s_type_addr, &setup); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 0864272..b9a94fc 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -25,7 +25,6 @@ #ifndef CX18_DRIVER_H #define CX18_DRIVER_H -#include <linux/version.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -410,6 +409,7 @@ struct cx18_stream { /* Videobuf for YUV video */ u32 pixelformat; + u32 vb_bytes_per_frame; struct list_head vb_capture; /* video capture queue */ spinlock_t vb_lock; struct timer_list vb_timeout; @@ -431,10 +431,6 @@ struct cx18_open_id { u32 open_id; int type; struct cx18 *cx; - - struct videobuf_queue vbuf_q; - spinlock_t s_lock; /* Protect vbuf_q */ - enum v4l2_buf_type vb_type; }; static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 07411f3..14cb961 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -784,8 +784,6 @@ int cx18_v4l2_close(struct file *filp) cx18_release_stream(s); } else { cx18_stop_capture(id, 0); - if (id->type == CX18_ENC_STREAM_TYPE_YUV) - videobuf_mmap_free(&id->vbuf_q); } kfree(id); mutex_unlock(&cx->serialize_lock); diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index e80134f..66b1c15 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -160,12 +160,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, pixfmt->priv = 0; if (id->type == CX18_ENC_STREAM_TYPE_YUV) { pixfmt->pixelformat = s->pixelformat; - /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) - UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) - pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; - else - pixfmt->sizeimage = pixfmt->height * 720 * 2; + pixfmt->sizeimage = s->vb_bytes_per_frame; pixfmt->bytesperline = 720; } else { pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; @@ -296,6 +291,12 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, return -EBUSY; s->pixelformat = fmt->fmt.pix.pixelformat; + /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + s->vb_bytes_per_frame = h * 720 * 3 / 2; + else + s->vb_bytes_per_frame = h * 720 * 2; mbus_fmt.width = cx->cxhdl.width = w; mbus_fmt.height = cx->cxhdl.height = h; @@ -463,14 +464,16 @@ static int cx18_s_register(struct file *file, void *fh, static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->pci_dev)); - vcap->version = CX18_DRIVER_VERSION; /* version */ vcap->capabilities = cx->v4l2_cap; /* capabilities */ + if (id->type == CX18_ENC_STREAM_TYPE_YUV) + vcap->capabilities |= V4L2_CAP_STREAMING; return 0; } diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index c07191e..0c7796e 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -196,7 +196,7 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, } /* If we've filled the buffer as per the callers res then dispatch it */ - if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) { + if (vb_buf->bytes_used >= s->vb_bytes_per_frame) { dispatch = 1; vb_buf->bytes_used = 0; } diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index 05fe6bd..b63fdfa 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -69,7 +69,7 @@ struct cx18_mailbox { /* Each command can have up to 6 arguments */ u32 args[MAX_MB_ARGUMENTS]; /* The return code can be one of the codes in the file cx23418.h. If the - command is completed successfuly, the error will be ERR_SYS_SUCCESS. + command is completed successfully, the error will be ERR_SYS_SUCCESS. If it is pending, the code is ERR_SYS_PENDING. If it failed, the error code would indicate the task from which the error originated and will be one of the errors in cx23418.h. In that case, the following diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 852f420..638cca1 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -138,6 +138,12 @@ static int cx18_prepare_buffer(struct videobuf_queue *q, buf->tvnorm = cx->std; s->pixelformat = pixelformat; + /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + s->vb_bytes_per_frame = height * 720 * 3 / 2; + else + s->vb_bytes_per_frame = height * 720 * 2; cx18_dma_free(q, s, buf); } @@ -154,6 +160,12 @@ static int cx18_prepare_buffer(struct videobuf_queue *q, buf->tvnorm = cx->std; s->pixelformat = pixelformat; + /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + s->vb_bytes_per_frame = height * 720 * 3 / 2; + else + s->vb_bytes_per_frame = height * 720 * 2; rc = videobuf_iolock(q, &buf->vb, NULL); if (rc != 0) goto fail; @@ -287,6 +299,7 @@ static void cx18_stream_init(struct cx18 *cx, int type) /* Assume the previous pixel default */ s->pixelformat = V4L2_PIX_FMT_HM12; + s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; } } diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h index cd189b6..fed48b6 100644 --- a/drivers/media/video/cx18/cx18-version.h +++ b/drivers/media/video/cx18/cx18-version.h @@ -23,12 +23,6 @@ #define CX18_VERSION_H #define CX18_DRIVER_NAME "cx18" -#define CX18_DRIVER_VERSION_MAJOR 1 -#define CX18_DRIVER_VERSION_MINOR 5 -#define CX18_DRIVER_VERSION_PATCHLEVEL 0 - -#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) -#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ - CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL) +#define CX18_VERSION "1.5.1" #endif diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile index 2c24843..b334897 100644 --- a/drivers/media/video/cx231xx/Makefile +++ b/drivers/media/video/cx231xx/Makefile @@ -8,9 +8,9 @@ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/dvb/dvb-usb diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c index 8d78134..53ff26e 100644 --- a/drivers/media/video/cx231xx/cx231xx-avcore.c +++ b/drivers/media/video/cx231xx/cx231xx-avcore.c @@ -355,6 +355,8 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev, case CX231XX_BOARD_HAUPPAUGE_EXETER: case CX231XX_BOARD_HAUPPAUGE_USBLIVE2: case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: if (avmode == POLARIS_AVMODE_ANALOGT_TV) { while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | FLD_PWRDN_ENABLE_PLL)) { @@ -1733,6 +1735,8 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard) break; case CX231XX_BOARD_CNXT_RDE_253S: case CX231XX_BOARD_CNXT_RDU_253S: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: func_mode = 0x01; break; default: diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 2270381..53dae2a 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -387,6 +387,7 @@ struct cx231xx_board cx231xx_boards[] = { .norm = V4L2_STD_NTSC, .no_alt_vanc = 1, .external_av = 1, + .dont_use_port_3 = 1, .input = {{ .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, @@ -532,6 +533,76 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = NULL, } }, }, + [CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL] = { + .name = "Hauppauge WinTV USB2 FM (PAL)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC] = { + .name = "Hauppauge WinTV USB2 FM (NTSC)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .norm = V4L2_STD_NTSC, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -553,6 +624,10 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_CNXT_RDE_250}, {USB_DEVICE(0x0572, 0x58A0), .driver_info = CX231XX_BOARD_CNXT_RDU_250}, + {USB_DEVICE(0x2040, 0xb110), + .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL}, + {USB_DEVICE(0x2040, 0xb111), + .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC}, {USB_DEVICE(0x2040, 0xb120), .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xb140), @@ -1051,6 +1126,9 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (assoc_desc->bFirstInterface != ifnum) { cx231xx_err(DRIVER_NAME ": Not found " "matching IAD interface\n"); + cx231xx_devused &= ~(1 << nr); + kfree(dev); + dev = NULL; return -ENODEV; } diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index abe500f..d4457f9 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c @@ -742,6 +742,8 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode) case CX231XX_BOARD_CNXT_RDU_253S: case CX231XX_BOARD_HAUPPAUGE_EXETER: case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); break; default: @@ -1381,6 +1383,8 @@ int cx231xx_dev_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_RDU_253S: case CX231XX_BOARD_HAUPPAUGE_EXETER: case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); break; default: diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index a69c24d..6e81f97 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -29,7 +29,6 @@ #include <linux/bitmap.h> #include <linux/usb.h> #include <linux/i2c.h> -#include <linux/version.h> #include <linux/mm.h> #include <linux/mutex.h> #include <linux/slab.h> @@ -45,7 +44,7 @@ #include "cx231xx.h" #include "cx231xx-vbi.h" -#define CX231XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) +#define CX231XX_VERSION "0.0.2" #define DRIVER_AUTHOR "Srinivasa Deevi <srinivasa.deevi@conexant.com>" #define DRIVER_DESC "Conexant cx231xx based USB video device driver" @@ -70,6 +69,7 @@ do {\ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX231XX_VERSION); static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; @@ -1179,7 +1179,8 @@ static int vidioc_enum_input(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; - unsigned int n; + u32 gen_stat; + unsigned int ret, n; n = i->index; if (n >= MAX_CX231XX_INPUT) @@ -1198,6 +1199,18 @@ static int vidioc_enum_input(struct file *file, void *priv, i->std = dev->vdev->tvnorms; + /* If they are asking about the active input, read signal status */ + if (n == dev->video_input) { + ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, + GEN_STAT, 2, &gen_stat, 4); + if (ret > 0) { + if ((gen_stat & FLD_VPRES) == 0x00) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if ((gen_stat & FLD_HLOCK) == 0x00) + i->status |= V4L2_IN_ST_NO_H_LOCK; + } + } + return 0; } @@ -1869,8 +1882,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = CX231XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_VBI_CAPTURE | #if 0 V4L2_CAP_SLICED_VBI_CAPTURE | @@ -2057,7 +2068,6 @@ static int radio_querycap(struct file *file, void *priv, strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = CX231XX_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } @@ -2570,11 +2580,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) { int ret; - cx231xx_info("%s: v4l2 driver version %d.%d.%d\n", - dev->name, - (CX231XX_VERSION_CODE >> 16) & 0xff, - (CX231XX_VERSION_CODE >> 8) & 0xff, - CX231XX_VERSION_CODE & 0xff); + cx231xx_info("%s: v4l2 driver version %s\n", + dev->name, CX231XX_VERSION); /* set default norm */ /*dev->norm = cx231xx_video_template.current_norm; */ diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 46dd840..2000bc6 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -43,7 +43,7 @@ #include "cx231xx-conf-reg.h" #define DRIVER_NAME "cx231xx" -#define PWR_SLEEP_INTERVAL 5 +#define PWR_SLEEP_INTERVAL 10 /* I2C addresses for control block in Cx231xx */ #define AFE_DEVICE_ADDRESS 0x60 @@ -67,6 +67,8 @@ #define CX231XX_BOARD_PV_XCAPTURE_USB 11 #define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12 #define CX231XX_BOARD_ICONBIT_U100 13 +#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14 +#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 @@ -112,7 +114,6 @@ V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) -#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2) #define SLEEP_S5H1432 30 #define CX23417_OSC_EN 8 diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index caab1bf..b391e9b 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -38,7 +38,7 @@ config VIDEO_CX23885 config MEDIA_ALTERA_CI tristate "Altera FPGA based CI module" depends on VIDEO_CX23885 && DVB_CORE - select STAPL_ALTERA + select ALTERA_STAPL ---help--- An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index 23293c7..f81f279 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -2,14 +2,14 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \ cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \ cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \ - cx23885-f300.o + cx23885-f300.o cx23885-alsa.o obj-$(CONFIG_VIDEO_CX23885) += cx23885.o obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c index 678539b..1fa8927 100644 --- a/drivers/media/video/cx23885/altera-ci.c +++ b/drivers/media/video/cx23885/altera-ci.c @@ -52,7 +52,6 @@ * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| * +-------+-------+-------+-------+-------+-------+-------+-------+ */ -#include <linux/version.h> #include <media/videobuf-dma-sg.h> #include <media/videobuf-dvb.h> #include "altera-ci.h" diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 9a98dc5..67c4a59 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1359,7 +1359,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 934185c..c3cf089 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -25,15 +25,21 @@ #include <linux/delay.h> #include <media/cx25840.h> #include <linux/firmware.h> +#include <misc/altera.h> -#include "../../../staging/altera-stapl/altera.h" #include "cx23885.h" #include "tuner-xc2028.h" +#include "netup-eeprom.h" #include "netup-init.h" #include "altera-ci.h" +#include "xc4000.h" #include "xc5000.h" #include "cx23888-ir.h" +static unsigned int netup_card_rev = 1; +module_param(netup_card_rev, int, 0644); +MODULE_PARM_DESC(netup_card_rev, + "NetUP Dual DVB-T/C CI card revision"); static unsigned int enable_885_ir; module_param(enable_885_ir, int, 0644); MODULE_PARM_DESC(enable_885_ir, @@ -100,12 +106,14 @@ struct cx23885_board cx23885_boards[] = { .vmux = CX25840_VIN7_CH3 | CX25840_VIN5_CH2 | CX25840_VIN2_CH1, + .amux = CX25840_AUDIO8, .gpio0 = 0, }, { .type = CX23885_VMUX_COMPOSITE1, .vmux = CX25840_VIN7_CH3 | CX25840_VIN4_CH2 | CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, .gpio0 = 0, }, { .type = CX23885_VMUX_SVIDEO, @@ -113,6 +121,7 @@ struct cx23885_board cx23885_boards[] = { CX25840_VIN4_CH2 | CX25840_VIN8_CH1 | CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, .gpio0 = 0, } }, }, @@ -147,7 +156,30 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1500] = { .name = "Hauppauge WinTV-HVR1500", + .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, /* 0xc2 >> 1 */ + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .gpio0 = 0, + } }, }, [CX23885_BOARD_HAUPPAUGE_HVR1200] = { .name = "Hauppauge WinTV-HVR1200", @@ -175,6 +207,34 @@ struct cx23885_board cx23885_boards[] = { .name = "Leadtek Winfast PxDVR3200 H", .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = { + .name = "Leadtek Winfast PxDVR3200 H XC4000", + .porta = CX23885_ANALOG_VIDEO, + .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_type = TUNER_XC4000, + .radio_addr = 0x61, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN2_CH1 | + CX25840_VIN5_CH2 | + CX25840_NONE0_CH3, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE1, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_VIN7_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN8_CH3 | + CX25840_COMPONENT_ON, + } }, + }, [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = { .name = "Compro VideoMate E650F", .portc = CX23885_MPEG_DVB, @@ -353,6 +413,31 @@ struct cx23885_board cx23885_boards[] = { .vmux = CX25840_COMPOSITE1, } }, }, + [CX23885_BOARD_MPX885] = { + .name = "MPX-885", + .porta = CX23885_ANALOG_VIDEO, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE1, + .amux = CX25840_AUDIO6, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE2, + .vmux = CX25840_COMPOSITE2, + .amux = CX25840_AUDIO6, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE3, + .vmux = CX25840_COMPOSITE3, + .amux = CX25840_AUDIO7, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE4, + .vmux = CX25840_COMPOSITE4, + .amux = CX25840_AUDIO7, + .gpio0 = 0, + } }, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -433,6 +518,10 @@ struct cx23885_subid cx23885_subids[] = { .subdevice = 0x6681, .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, }, { + .subvendor = 0x107d, + .subdevice = 0x6f39, + .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000, + }, { .subvendor = 0x185b, .subdevice = 0xe800, .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, @@ -749,6 +838,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: @@ -909,6 +999,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x000f000f); break; case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: @@ -1097,12 +1188,19 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1200: case CX23885_BOARD_HAUPPAUGE_HVR1400: - case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: /* FIXME: Implement me */ break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + ret = cx23888_ir_probe(dev); + if (ret) + break; + dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); + v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, + ir_rx_pin_cfg_count, ir_rx_pin_cfg); + break; case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: ret = cx23888_ir_probe(dev); @@ -1156,6 +1254,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) void cx23885_ir_fini(struct cx23885_dev *dev) { switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: cx23885_irq_remove(dev, PCI_MSK_IR); @@ -1199,6 +1298,7 @@ int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) { switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: if (dev->sd_ir) @@ -1325,6 +1425,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1700: case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1275: @@ -1353,16 +1454,20 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1700: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_MYGICA_X8506: case CX23885_BOARD_MAGICPRO_PROHDTVE2: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_MPX885: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); @@ -1383,6 +1488,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) const struct firmware *fw; const char *filename = "dvb-netup-altera-01.fw"; char *action = "configure"; + static struct netup_card_info cinfo; struct altera_config netup_config = { .dev = dev, .action = action, @@ -1391,6 +1497,21 @@ void cx23885_card_setup(struct cx23885_dev *dev) netup_initialize(dev); + netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); + if (netup_card_rev) + cinfo.rev = netup_card_rev; + + switch (cinfo.rev) { + case 0x4: + filename = "dvb-netup-altera-04.fw"; + break; + default: + filename = "dvb-netup-altera-01.fw"; + break; + } + printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n", + cinfo.rev, filename); + ret = request_firmware(&fw, filename, &dev->pci->dev); if (ret != 0) printk(KERN_ERR "did not find the firmware file. (%s) " diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 419777a..40e68b2 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -42,6 +42,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX23885_VERSION); static unsigned int debug; module_param(debug, int, 0644); @@ -53,7 +54,7 @@ MODULE_PARM_DESC(card, "card type"); #define dprintk(level, fmt, arg...)\ do { if (debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ } while (0) static unsigned int cx23885_devcount; @@ -154,12 +155,12 @@ static struct sram_channel cx23885_sram_channels[] = { .cnt2_reg = DMA5_CNT2, }, [SRAM_CH07] = { - .name = "ch7", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TV Audio", + .cmds_start = 0x10190, + .ctrl_start = 0x10480, + .cdt = 0x10a00, + .fifo_start = 0x7000, + .fifo_size = 0x1000, .ptr1_reg = DMA6_PTR1, .ptr2_reg = DMA6_PTR2, .cnt1_reg = DMA6_CNT1, @@ -1081,10 +1082,10 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int lines, unsigned int lpi) { struct scatterlist *sg; - unsigned int line, todo; + unsigned int line, todo, sol; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -1097,16 +1098,22 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, offset -= sg_dma_len(sg); sg++; } + + if (lpi && line > 0 && !(line % lpi)) + sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; + else + sol = RISC_SOL; + if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL| + *(rp++) = cpu_to_le32(RISC_WRITE|sol| (sg_dma_len(sg)-offset)); *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ @@ -1163,10 +1170,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines, 0); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines, 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1174,11 +1181,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, return 0; } -static int cx23885_risc_databuffer(struct pci_dev *pci, +int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + unsigned int lines, unsigned int lpi) { u32 instructions; __le32 *rp; @@ -1198,7 +1205,55 @@ static int cx23885_risc_databuffer(struct pci_dev *pci, /* write risc instructions */ rp = risc->cpu; - rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, + bpl, 0, lines, lpi); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) +{ + u32 instructions, fields; + __le32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) + / PAGE_SIZE + lines); + instructions += 2; + rc = btcx_riscmem_alloc(pci, risc, instructions*12); + if (rc < 0) + return rc; + /* write risc instructions */ + rp = risc->cpu; + + /* Sync to line 6, so US CC line 21 will appear in line '12' + * in the userland vbi payload */ + if (UNSET != top_offset) + rp = cx23885_risc_field(rp, sglist, top_offset, 6, + bpl, padding, lines, 0); + + if (UNSET != bottom_offset) + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, + bpl, padding, lines, 0); + + /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1206,6 +1261,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci, return 0; } + int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value) { @@ -1516,7 +1572,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, videobuf_to_dma(&buf->vb)->sglist, - buf->vb.width, buf->vb.height); + buf->vb.width, buf->vb.height, 0); } buf->vb.state = VIDEOBUF_PREPARED; return 0; @@ -1740,15 +1796,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; u32 vida_status, vida_mask; + u32 audint_status, audint_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; + int audint_count = 0; bool subdev_handled; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx23885_irq_get_mask(dev); vida_status = cx_read(VID_A_INT_STAT); vida_mask = cx_read(VID_A_INT_MSK); + audint_status = cx_read(AUDIO_INT_INT_STAT); + audint_mask = cx_read(AUDIO_INT_INT_MSK); ts1_status = cx_read(VID_B_INT_STAT); ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); @@ -1758,12 +1818,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) goto out; vida_count = cx_read(VID_A_GPCNT); + audint_count = cx_read(AUD_INT_A_GPCNT); ts1_count = cx_read(ts1->reg_gpcnt); ts2_count = cx_read(ts2->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask); dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", vida_status, vida_mask, vida_count); + dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n", + audint_status, audint_mask, audint_count); dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count); dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", @@ -1860,6 +1923,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if (vida_status) handled += cx23885_video_irq(dev, vida_status); + if (audint_status) + handled += cx23885_audio_irq(dev, audint_status, audint_mask); + if (pci_status & PCI_MSK_IR) { subdev_handled = false; v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine, @@ -2147,14 +2213,8 @@ static struct pci_driver cx23885_pci_driver = { static int __init cx23885_init(void) { - printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", - (CX23885_VERSION_CODE >> 16) & 0xff, - (CX23885_VERSION_CODE >> 8) & 0xff, - CX23885_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx23885 driver version %s loaded\n", + CX23885_VERSION); return pci_register_driver(&cx23885_pci_driver); } @@ -2165,5 +2225,3 @@ static void __exit cx23885_fini(void) module_init(cx23885_init); module_exit(cx23885_fini); - -/* ----------------------------------------------------------- */ diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 2b5cd21..f0482b2 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -37,6 +37,7 @@ #include "tda8290.h" #include "tda18271.h" #include "lgdt330x.h" +#include "xc4000.h" #include "xc5000.h" #include "max2165.h" #include "tda10048.h" @@ -921,6 +922,31 @@ static int dvb_register(struct cx23885_tsport *port) fe->ops.tuner_ops.set_config(fe, &ctl); } break; + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000: + i2c_bus = &dev->i2c_bus[0]; + + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_xc3028, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc4000_config cfg = { + .i2c_address = 0x61, + .default_pm = 0, + .dvb_amplitude = 134, + .set_smoothedcvbs = 1, + .if_khz = 4560 + }; + + fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, + &dev->i2c_bus[1].i2c_adap, &cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc4000 attach failed\n", + dev->name); + goto frontend_detach; + } + } + break; case CX23885_BOARD_TBS_6920: i2c_bus = &dev->i2c_bus[1]; @@ -1249,7 +1275,7 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) * implement MFE support. */ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); - if (fe0->dvb.frontend) + if (fe0 && fe0->dvb.frontend) videobuf_dvb_unregister_bus(&port->frontends); switch (port->dev->board) { diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 307ff54..0ff7a9e 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -287,6 +287,7 @@ static char *i2c_devs[128] = { [0x32 >> 1] = "cx24227", [0x88 >> 1] = "cx25837", [0x84 >> 1] = "tda8295", + [0x98 >> 1] = "flatiron", [0xa0 >> 1] = "eeprom", [0xc0 >> 1] = "tuner/mt2131/tda8275", [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028", diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index e97cafd..ce765e3 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -82,6 +82,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) return; switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_TEVII_S470: @@ -133,6 +134,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev) v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: @@ -229,6 +231,9 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev) v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); } + flush_work_sync(&dev->cx25840_work); + flush_work_sync(&dev->ir_rx_work); + flush_work_sync(&dev->ir_tx_work); } static void cx23885_input_ir_close(struct rc_dev *rc) @@ -257,6 +262,7 @@ int cx23885_input_init(struct cx23885_dev *dev) return -ENODEV; switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index c87ac68..a99936e 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -203,6 +203,7 @@ Channel manager Data Structure entry = 20 DWORD #define SD2_BIAS_CTRL 0x0000000A #define AMP_BIAS_CTRL 0x0000000C #define CH_PWR_CTRL1 0x0000000E +#define FLD_CH_SEL (1 << 3) #define CH_PWR_CTRL2 0x0000000F #define DSM_STATUS1 0x00000010 #define DSM_STATUS2 0x00000011 @@ -271,7 +272,9 @@ Channel manager Data Structure entry = 20 DWORD #define VID_BC_MSK_OPC_ERR (1 << 16) #define VID_BC_MSK_SYNC (1 << 12) #define VID_BC_MSK_OF (1 << 8) +#define VID_BC_MSK_VBI_RISCI2 (1 << 5) #define VID_BC_MSK_RISCI2 (1 << 4) +#define VID_BC_MSK_VBI_RISCI1 (1 << 1) #define VID_BC_MSK_RISCI1 1 #define VID_C_INT_MSK 0x00040040 diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index c0b6038..a1154f0 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -41,6 +41,12 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); /* ------------------------------------------------------------------ */ +#define VBI_LINE_LENGTH 1440 +#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ +#define NTSC_VBI_END_LINE 21 +#define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1) + + int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) { @@ -49,43 +55,86 @@ int cx23885_vbi_fmt(struct file *file, void *priv, if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ - f->fmt.vbi.sampling_rate = 28636363; + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; + f->fmt.vbi.sampling_rate = 27000000; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 0; + f->fmt.vbi.flags = 0; f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 273; - + f->fmt.vbi.count[0] = 17; + f->fmt.vbi.start[1] = 263 + 10 + 1; + f->fmt.vbi.count[1] = 17; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ f->fmt.vbi.sampling_rate = 35468950; f->fmt.vbi.start[0] = 7 - 1; f->fmt.vbi.start[1] = 319 - 1; } + return 0; } +/* We're given the Video Interrupt status register. + * The cx23885_video_irq() func has already validated + * the potential error bits, we just need to + * deal with vbi payload and return indication if + * we actually processed any payload. + */ +int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) +{ + u32 count; + int handled = 0; + + if (status & VID_BC_MSK_VBI_RISCI1) { + dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__); + spin_lock(&dev->slock); + count = cx_read(VID_A_GPCNT); + cx23885_video_wakeup(dev, &dev->vbiq, count); + spin_unlock(&dev->slock); + handled++; + } + + if (status & VID_BC_MSK_VBI_RISCI2) { + dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__); + dprintk(2, "stopper vbi\n"); + spin_lock(&dev->slock); + cx23885_restart_vbi_queue(dev, &dev->vbiq); + spin_unlock(&dev->slock); + handled++; + } + + return handled; +} + static int cx23885_start_vbi_dma(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) { + dprintk(1, "%s()\n", __func__); + /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], buf->vb.width, buf->risc.dma); /* reset counter */ + cx_write(VID_A_GPCNT_CTL, 3); + cx_write(VID_A_VBI_CTRL, 3); + cx_write(VBI_A_GPCNT_CTL, 3); q->count = 1; - /* enable irqs */ + /* enable irq */ cx23885_irq_add_enable(dev, 0x01); cx_set(VID_A_INT_MSK, 0x000022); /* start dma */ cx_set(DEV_CNTRL2, (1<<5)); - cx_set(VID_A_DMA_CTL, 0x00000022); + cx_set(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */ return 0; } -static int cx23885_restart_vbi_queue(struct cx23885_dev *dev, +int cx23885_restart_vbi_queue(struct cx23885_dev *dev, struct cx23885_dmaqueue *q) { struct cx23885_buffer *buf; @@ -102,7 +151,7 @@ static int cx23885_restart_vbi_queue(struct cx23885_dev *dev, buf = list_entry(item, struct cx23885_buffer, vb.queue); buf->count = q->count++; } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); return 0; } @@ -113,8 +162,7 @@ void cx23885_vbi_timeout(unsigned long data) struct cx23885_buffer *buf; unsigned long flags; - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); - + /* Stop the VBI engine */ cx_clear(VID_A_DMA_CTL, 0x22); spin_lock_irqsave(&dev->slock, flags); @@ -132,7 +180,7 @@ void cx23885_vbi_timeout(unsigned long data) } /* ------------------------------------------------------------------ */ -#define VBI_LINE_LENGTH 2048 +#define VBI_LINE_LENGTH 1440 #define VBI_LINE_COUNT 17 static int @@ -173,7 +221,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, rc = videobuf_iolock(q, &buf->vb, NULL); if (0 != rc) goto fail; - cx23885_risc_buffer(dev->pci, &buf->risc, + cx23885_risc_vbibuffer(dev->pci, &buf->risc, dma->sglist, 0, buf->vb.width * buf->vb.height, buf->vb.width, 0, @@ -207,7 +255,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) cx23885_start_vbi_dma(dev, q, buf); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); dprintk(2, "[%p/%d] vbi_queue - first active\n", buf, buf->vb.i); diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index ee57f6b..e730b92 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -37,6 +37,8 @@ #include "cx23885-ioctl.h" #include "tuner-xc2028.h" +#include <media/cx25840.h> + MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); @@ -69,14 +71,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); #define dprintk(level, fmt, arg...)\ do { if (video_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ } while (0) /* ------------------------------------------------------------------- */ /* static data */ #define FORMAT_FLAGS_PACKED 0x01 - +#if 0 static struct cx23885_fmt formats[] = { { .name = "8 bpp, gray", @@ -130,6 +132,23 @@ static struct cx23885_fmt formats[] = { .flags = FORMAT_FLAGS_PACKED, }, }; +#else +static struct cx23885_fmt formats[] = { + { +#if 0 + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { +#endif + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + } +}; +#endif static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) { @@ -139,7 +158,12 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) if (formats[i].fourcc == fourcc) return formats+i; - printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); + printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__, + (fourcc & 0xff), + ((fourcc >> 8) & 0xff), + ((fourcc >> 16) & 0xff), + ((fourcc >> 24) & 0xff) + ); return NULL; } @@ -171,7 +195,7 @@ static struct cx23885_ctrl cx23885_ctls[] = { .id = V4L2_CID_CONTRAST, .name = "Contrast", .minimum = 0, - .maximum = 0xff, + .maximum = 0x7f, .step = 1, .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, @@ -184,10 +208,10 @@ static struct cx23885_ctrl cx23885_ctls[] = { .v = { .id = V4L2_CID_HUE, .name = "Hue", - .minimum = 0, - .maximum = 0xff, + .minimum = -127, + .maximum = 128, .step = 1, - .default_value = 0x7f, + .default_value = 0x0, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, @@ -202,9 +226,9 @@ static struct cx23885_ctrl cx23885_ctls[] = { .id = V4L2_CID_SATURATION, .name = "Saturation", .minimum = 0, - .maximum = 0xff, + .maximum = 0x7f, .step = 1, - .default_value = 0x7f, + .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 0, @@ -258,8 +282,8 @@ static const u32 *ctrl_classes[] = { NULL }; -static void cx23885_video_wakeup(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, u32 count) +void cx23885_video_wakeup(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_buffer *buf; int bc; @@ -393,6 +417,71 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, mutex_unlock(&dev->lock); } +static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) +{ + /* 8 bit registers, 8 bit values */ + u8 buf[] = { reg, data }; + + struct i2c_msg msg = { .addr = 0x98 >> 1, + .flags = 0, .buf = buf, .len = 2 }; + + return i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); +} + +static u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg) +{ + /* 8 bit registers, 8 bit values */ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + { .addr = 0x98 >> 1, .flags = 0, .buf = b0, .len = 1 }, + { .addr = 0x98 >> 1, .flags = I2C_M_RD, .buf = b1, .len = 1 } + }; + + ret = i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg[0], 2); + if (ret != 2) + printk(KERN_ERR "%s() error\n", __func__); + + return b1[0]; +} + +static void cx23885_flatiron_dump(struct cx23885_dev *dev) +{ + int i; + dprintk(1, "Flatiron dump\n"); + for (i = 0; i < 0x24; i++) { + dprintk(1, "FI[%02x] = %02x\n", i, + cx23885_flatiron_read(dev, i)); + } +} + +static int cx23885_flatiron_mux(struct cx23885_dev *dev, int input) +{ + u8 val; + dprintk(1, "%s(input = %d)\n", __func__, input); + + if (input == 1) + val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) & ~FLD_CH_SEL; + else if (input == 2) + val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) | FLD_CH_SEL; + else + return -EINVAL; + + val |= 0x20; /* Enable clock to delta-sigma and dec filter */ + + cx23885_flatiron_write(dev, CH_PWR_CTRL1, val); + + /* Wake up */ + cx23885_flatiron_write(dev, CH_PWR_CTRL2, 0); + + if (video_debug) + cx23885_flatiron_dump(dev); + + return 0; +} + static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) { dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", @@ -413,27 +502,59 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) v4l2_subdev_call(dev->sd_cx25840, video, s_routing, INPUT(input)->vmux, 0, 0); + if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || + (dev->board == CX23885_BOARD_MPX885)) { + /* Configure audio routing */ + v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, + INPUT(input)->amux, 0, 0); + + if (INPUT(input)->amux == CX25840_AUDIO7) + cx23885_flatiron_mux(dev, 1); + else if (INPUT(input)->amux == CX25840_AUDIO6) + cx23885_flatiron_mux(dev, 2); + } + return 0; } -/* ------------------------------------------------------------------ */ -static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, - unsigned int height, enum v4l2_field field) +static int cx23885_audio_mux(struct cx23885_dev *dev, unsigned int input) { - dprintk(1, "%s()\n", __func__); + dprintk(1, "%s(input=%d)\n", __func__, input); + + /* The baseband video core of the cx23885 has two audio inputs. + * LR1 and LR2. In almost every single case so far only HVR1xxx + * cards we've only ever supported LR1. Time to support LR2, + * which is available via the optional white breakout header on + * the board. + * We'll use a could of existing enums in the card struct to allow + * devs to specify which baseband input they need, or just default + * to what we've always used. + */ + if (INPUT(input)->amux == CX25840_AUDIO7) + cx23885_flatiron_mux(dev, 1); + else if (INPUT(input)->amux == CX25840_AUDIO6) + cx23885_flatiron_mux(dev, 2); + else { + /* Not specifically defined, assume the default. */ + cx23885_flatiron_mux(dev, 1); + } + return 0; } +/* ------------------------------------------------------------------ */ static int cx23885_start_video_dma(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) { dprintk(1, "%s()\n", __func__); + /* Stop the dma/fifo before we tamper with it's risc programs */ + cx_clear(VID_A_DMA_CTL, 0x11); + /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], buf->bpl, buf->risc.dma); - cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); @@ -748,7 +869,7 @@ static int video_open(struct file *file) fh->type = type; fh->width = 320; fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, &dev->pci->dev, &dev->slock, @@ -757,6 +878,14 @@ static int video_open(struct file *file) sizeof(struct cx23885_buffer), fh, NULL); + videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct cx23885_buffer), + fh, NULL); + + dprintk(1, "post videobuf_queue_init()\n"); return 0; @@ -884,8 +1013,9 @@ static int cx23885_get_control(struct cx23885_dev *dev, static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { - dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" - " (disabled - no action)\n", __func__); + dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); + call_all(dev, core, s_ctrl, ctl); + return 0; } @@ -1000,7 +1130,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | @@ -1060,13 +1189,22 @@ static int vidioc_streamon(struct file *file, void *priv, struct cx23885_dev *dev = fh->dev; dprintk(1, "%s()\n", __func__); - if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; if (unlikely(i != fh->type)) return -EINVAL; if (unlikely(!res_get(dev, fh, get_resource(fh)))) return -EBUSY; + + /* Don't start VBI streaming unless vida streaming + * has already started. + */ + if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) && + ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) + return -EINVAL; + return videobuf_streamon(get_queue(fh)); } @@ -1077,7 +1215,8 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) int err, res; dprintk(1, "%s()\n", __func__); - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; if (i != fh->type) return -EINVAL; @@ -1120,7 +1259,7 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) dprintk(1, "%s()\n", __func__); n = i->index; - if (n >= 4) + if (n >= MAX_CX23885_INPUT) return -EINVAL; if (0 == INPUT(n)->type) @@ -1134,6 +1273,11 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) i->type = V4L2_INPUT_TYPE_TUNER; i->std = CX23885_NORMS; } + + /* Two selectable audio inputs for non-tv inputs */ + if (INPUT(n)->type != CX23885_VMUX_TELEVISION) + i->audioset = 0x3; + return 0; } @@ -1160,13 +1304,20 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) dprintk(1, "%s(%d)\n", __func__, i); - if (i >= 4) { + if (i >= MAX_CX23885_INPUT) { dprintk(1, "%s() -EINVAL\n", __func__); return -EINVAL; } + if (INPUT(i)->type == 0) + return -EINVAL; + mutex_lock(&dev->lock); cx23885_video_mux(dev, i); + + /* By default establish the default audio input for the card also */ + /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */ + cx23885_audio_mux(dev, i); mutex_unlock(&dev->lock); return 0; } @@ -1186,6 +1337,64 @@ static int vidioc_log_status(struct file *file, void *priv) return 0; } +static int cx23885_query_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + static const char *iname[] = { + [0] = "Baseband L/R 1", + [1] = "Baseband L/R 2", + }; + unsigned int n; + dprintk(1, "%s()\n", __func__); + + n = i->index; + if (n >= 2) + return -EINVAL; + + memset(i, 0, sizeof(*i)); + i->index = n; + strcpy(i->name, iname[n]); + i->capability = V4L2_AUDCAP_STEREO; + i->mode = V4L2_AUDMODE_AVL; + return 0; + +} + +static int vidioc_enum_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + return cx23885_query_audinput(file, priv, i); +} + +static int vidioc_g_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + i->index = dev->audinput; + dprintk(1, "%s(input=%d)\n", __func__, i->index); + + return cx23885_query_audinput(file, priv, i); +} + +static int vidioc_s_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + if (i->index >= 2) + return -EINVAL; + + dprintk(1, "%s(%d)\n", __func__, i->index); + + dev->audinput = i->index; + + /* Skip the audio defaults from the cards struct, caller wants + * directly touch the audio mux hardware. */ + cx23885_flatiron_mux(dev, dev->audinput + 1); + return 0; +} + static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qctrl) { @@ -1222,10 +1431,8 @@ static int vidioc_g_tuner(struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - t->signal = 0xffff ; /* LOCKED */ + + call_all(dev, tuner, g_tuner, t); return 0; } @@ -1238,6 +1445,9 @@ static int vidioc_s_tuner(struct file *file, void *priv, return -EINVAL; if (0 != t->index) return -EINVAL; + /* Update the A/V core */ + call_all(dev, tuner, s_tuner, t); + return 0; } @@ -1303,10 +1513,6 @@ static void cx23885_vid_timeout(unsigned long data) struct cx23885_buffer *buf; unsigned long flags; - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); - - cx_clear(VID_A_DMA_CTL, 0x11); - spin_lock_irqsave(&dev->slock, flags); while (!list_empty(&q->active)) { buf = list_entry(q->active.next, @@ -1314,7 +1520,7 @@ static void cx23885_vid_timeout(unsigned long data) list_del(&buf->vb.queue); buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); - printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", + printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n", dev->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); } @@ -1330,27 +1536,43 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) mask = cx_read(VID_A_INT_MSK); if (0 == (status & mask)) return handled; + cx_write(VID_A_INT_STAT, status); - dprintk(2, "%s() status = 0x%08x\n", __func__, status); - /* risc op code error */ - if (status & (1 << 16)) { - printk(KERN_WARNING "%s/0: video risc op code error\n", - dev->name); - cx_clear(VID_A_DMA_CTL, 0x11); - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + /* risc op code error, fifo overflow or line sync detection error */ + if ((status & VID_BC_MSK_OPC_ERR) || + (status & VID_BC_MSK_SYNC) || + (status & VID_BC_MSK_OF)) { + + if (status & VID_BC_MSK_OPC_ERR) { + dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", + VID_BC_MSK_OPC_ERR); + printk(KERN_WARNING "%s: video risc op code error\n", + dev->name); + cx23885_sram_channel_dump(dev, + &dev->sram_channels[SRAM_CH01]); + } + + if (status & VID_BC_MSK_SYNC) + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x) " + "video lines miss-match\n", + VID_BC_MSK_SYNC); + + if (status & VID_BC_MSK_OF) + dprintk(7, " (VID_BC_MSK_OF 0x%08x) fifo overflow\n", + VID_BC_MSK_OF); + } - /* risc1 y */ - if (status & 0x01) { + /* Video */ + if (status & VID_BC_MSK_RISCI1) { spin_lock(&dev->slock); count = cx_read(VID_A_GPCNT); cx23885_video_wakeup(dev, &dev->vidq, count); spin_unlock(&dev->slock); handled++; } - /* risc2 y */ - if (status & 0x10) { + if (status & VID_BC_MSK_RISCI2) { dprintk(2, "stopper video\n"); spin_lock(&dev->slock); cx23885_restart_video_queue(dev, &dev->vidq); @@ -1358,6 +1580,9 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) handled++; } + /* Allow the VBI framework to process it's payload */ + handled += cx23885_vbi_irq(dev, status); + return handled; } @@ -1406,6 +1631,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_register = cx23885_g_register, .vidioc_s_register = cx23885_s_register, #endif + .vidioc_enumaudio = vidioc_enum_audinput, + .vidioc_g_audio = vidioc_g_audinput, + .vidioc_s_audio = vidioc_s_audinput, }; static struct video_device cx23885_vbi_template; @@ -1430,6 +1658,14 @@ void cx23885_video_unregister(struct cx23885_dev *dev) dprintk(1, "%s()\n", __func__); cx23885_irq_remove(dev, 0x01); + if (dev->vbi_dev) { + if (video_is_registered(dev->vbi_dev)) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + btcx_riscmem_free(dev->pci, &dev->vbiq.stopper); + } if (dev->video_dev) { if (video_is_registered(dev->video_dev)) video_unregister_device(dev->video_dev); @@ -1439,6 +1675,9 @@ void cx23885_video_unregister(struct cx23885_dev *dev) btcx_riscmem_free(dev->pci, &dev->vidq.stopper); } + + if (dev->audio_dev) + cx23885_audio_unregister(dev); } int cx23885_video_register(struct cx23885_dev *dev) @@ -1464,7 +1703,14 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, VID_A_DMA_CTL, 0x11, 0x00); - /* Don't enable VBI yet */ + /* init vbi dma queues */ + INIT_LIST_HEAD(&dev->vbiq.active); + INIT_LIST_HEAD(&dev->vbiq.queued); + dev->vbiq.timeout.function = cx23885_vbi_timeout; + dev->vbiq.timeout.data = (unsigned long)dev; + init_timer(&dev->vbiq.timeout); + cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper, + VID_A_DMA_CTL, 0x22, 0x00); cx23885_irq_add_enable(dev, 0x01); @@ -1505,8 +1751,7 @@ int cx23885_video_register(struct cx23885_dev *dev) } } - - /* register v4l devices */ + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, @@ -1516,13 +1761,31 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->name); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", + printk(KERN_INFO "%s: registered device %s [v4l2]\n", dev->name, video_device_node_name(dev->video_dev)); + + /* register VBI device */ + dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, + &cx23885_vbi_template, "vbi"); + err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register vbi device\n", + dev->name); + goto fail_unreg; + } + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->vbi_dev)); + + /* Register ALSA audio device */ + dev->audio_dev = cx23885_audio_register(dev); + /* initial device configuration */ mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, dev->tvnorm); init_controls(dev); cx23885_video_mux(dev, 0); + cx23885_audio_mux(dev, 0); mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index c186473..b49036f 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -36,10 +36,9 @@ #include "cx23885-reg.h" #include "media/cx2341x.h" -#include <linux/version.h> #include <linux/mutex.h> -#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 2) +#define CX23885_VERSION "0.0.3" #define UNSET (-1U) @@ -86,6 +85,8 @@ #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28 #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 +#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 +#define CX23885_BOARD_MPX885 32 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -192,6 +193,7 @@ struct cx23885_buffer { struct cx23885_input { enum cx23885_itype type; unsigned int vmux; + unsigned int amux; u32 gpio0, gpio1, gpio2, gpio3; }; @@ -318,6 +320,34 @@ struct cx23885_kernel_ir { struct rc_dev *rc; }; +struct cx23885_audio_buffer { + unsigned int bpl; + struct btcx_riscmem risc; + struct videobuf_dmabuf dma; +}; + +struct cx23885_audio_dev { + struct cx23885_dev *dev; + + struct pci_dev *pci; + + struct snd_card *card; + + spinlock_t lock; + + atomic_t count; + + unsigned int dma_size; + unsigned int period_size; + unsigned int num_periods; + + struct videobuf_dmabuf *dma_risc; + + struct cx23885_audio_buffer *buf; + + struct snd_pcm_substream *substream; +}; + struct cx23885_dev { atomic_t refcount; struct v4l2_device v4l2_dev; @@ -362,6 +392,7 @@ struct cx23885_dev { /* Analog video */ u32 resources; unsigned int input; + unsigned int audinput; /* Selectable audio input */ u32 tvaudio; v4l2_std_id tvnorm; unsigned int tuner_type; @@ -400,6 +431,9 @@ struct cx23885_dev { atomic_t v4l_reader_count; struct cx23885_tvnorm encodernorm; + /* Analog raw audio */ + struct cx23885_audio_dev *audio_dev; + }; static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) @@ -478,6 +512,11 @@ extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); +extern int cx23885_risc_vbibuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines); + void cx23885_cancel_buffers(struct cx23885_tsport *port); extern int cx23885_restart_queue(struct cx23885_tsport *port, @@ -533,6 +572,8 @@ extern void cx23885_free_buffer(struct videobuf_queue *q, extern int cx23885_video_register(struct cx23885_dev *dev); extern void cx23885_video_unregister(struct cx23885_dev *dev); extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); +extern void cx23885_video_wakeup(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, u32 count); /* ----------------------------------------------------------- */ /* cx23885-vbi.c */ @@ -540,6 +581,9 @@ extern int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f); extern void cx23885_vbi_timeout(unsigned long data); extern struct videobuf_queue_ops cx23885_vbi_qops; +extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q); +extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status); /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); @@ -563,6 +607,18 @@ extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); +/* ----------------------------------------------------------- */ +/* cx23885-alsa.c */ +extern struct cx23885_audio_dev *cx23885_audio_register( + struct cx23885_dev *dev); +extern void cx23885_audio_unregister(struct cx23885_dev *dev); +extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask); +extern int cx23885_risc_databuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines, + unsigned int lpi); /* ----------------------------------------------------------- */ /* tv norms */ diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c index e37be6f..bb1ce34 100644 --- a/drivers/media/video/cx23885/cx23888-ir.c +++ b/drivers/media/video/cx23885/cx23888-ir.c @@ -673,7 +673,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, unsigned int i, n; union cx23888_ir_fifo_rec *p; - unsigned u, v; + unsigned u, v, w; n = count / sizeof(union cx23888_ir_fifo_rec) * sizeof(union cx23888_ir_fifo_rec); @@ -692,11 +692,12 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { /* Assume RTO was because of no IR light input */ u = 0; - v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); + w = 1; } else { u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; if (invert) u = u ? 0 : 1; + w = 0; } v = (unsigned) pulse_width_count_to_ns( @@ -707,9 +708,12 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, init_ir_raw_event(&p->ir_core_data); p->ir_core_data.pulse = u; p->ir_core_data.duration = v; + p->ir_core_data.timeout = w; - v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n", - v, u ? "mark" : "space"); + v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s %s\n", + v, u ? "mark" : "space", w ? "(timed out)" : ""); + if (w) + v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); } return 0; } diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile index 2ee96d3..dc40dde 100644 --- a/drivers/media/video/cx25840/Makefile +++ b/drivers/media/video/cx25840/Makefile @@ -3,4 +3,4 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ obj-$(CONFIG_VIDEO_CX25840) += cx25840.o -EXTRA_CFLAGS += -Idrivers/media/video +ccflags-y += -Idrivers/media/video diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 34b96c7..005f110 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -480,6 +480,7 @@ void cx25840_audio_set_path(struct i2c_client *client) static void set_volume(struct i2c_client *client, int volume) { + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); int vol; /* Convert the volume to msp3400 values (0-127) */ @@ -495,7 +496,14 @@ static void set_volume(struct i2c_client *client, int volume) } /* PATH1_VOLUME */ - cx25840_write(client, 0x8d4, 228 - (vol * 2)); + if (is_cx2388x(state)) { + /* for cx23885 volume doesn't work, + * the calculation always results in + * e4 regardless. + */ + cx25840_write(client, 0x8d4, volume); + } else + cx25840_write(client, 0x8d4, 228 - (vol * 2)); } static void set_balance(struct i2c_client *client, int balance) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index b7ee2ae..cd99764 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -702,6 +702,13 @@ static void cx231xx_initialize(struct i2c_client *client) /* start microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0x10); + + /* CC raw enable */ + cx25840_write(client, 0x404, 0x0b); + + /* CC on */ + cx25840_write(client, 0x42f, 0x66); + cx25840_write4(client, 0x474, 0x1e1e601a); } /* ----------------------------------------------------------------------- */ @@ -1067,6 +1074,18 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write(client, 0x919, 0x01); } + if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) || + (aud_input == CX25840_AUDIO6))) { + /* Configure audio from LR1 or LR2 input */ + cx25840_write4(client, 0x910, 0); + cx25840_write4(client, 0x8d0, 0x63073); + } else + if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) { + /* Configure audio from tuner/sif input */ + cx25840_write4(client, 0x910, 0x12b000c9); + cx25840_write4(client, 0x8d0, 0x1f063870); + } + return 0; } diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c index 7eb79af..13c380e 100644 --- a/drivers/media/video/cx25840/cx25840-ir.c +++ b/drivers/media/video/cx25840/cx25840-ir.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/kfifo.h> +#include <linux/module.h> #include <media/cx25840.h> #include <media/rc-core.h> @@ -668,7 +669,7 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, u16 divider; unsigned int i, n; union cx25840_ir_fifo_rec *p; - unsigned u, v; + unsigned u, v, w; if (ir_state == NULL) return -ENODEV; @@ -694,11 +695,12 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { /* Assume RTO was because of no IR light input */ u = 0; - v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n"); + w = 1; } else { u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; if (invert) u = u ? 0 : 1; + w = 0; } v = (unsigned) pulse_width_count_to_ns( @@ -709,9 +711,12 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, init_ir_raw_event(&p->ir_core_data); p->ir_core_data.pulse = u; p->ir_core_data.duration = v; + p->ir_core_data.timeout = w; - v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n", - v, u ? "mark" : "space"); + v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s %s\n", + v, u ? "mark" : "space", w ? "(timed out)" : ""); + if (w) + v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n"); } return 0; } diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 5b7e267..c1a2785 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 423c1af..68d1240 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -113,6 +113,8 @@ MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); MODULE_AUTHOR("Ricardo Cerqueira"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); + MODULE_SUPPORTED_DEVICE("{{Conexant,23881}," "{{Conexant,23882}," "{{Conexant,23883}"); @@ -973,14 +975,8 @@ static struct pci_driver cx88_audio_pci_driver = { */ static int __init cx88_audio_init(void) { - printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx2388x alsa driver version %s loaded\n", + CX88_VERSION); return pci_register_driver(&cx88_audio_pci_driver); } @@ -994,10 +990,3 @@ static void __exit cx88_audio_fini(void) module_init(cx88_audio_init); module_exit(cx88_audio_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 11e49bb..e46446a 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -42,6 +42,7 @@ MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); static unsigned int mpegbufs = 32; module_param(mpegbufs,int,0644); @@ -730,7 +731,6 @@ static int vidioc_querycap (struct file *file, void *priv, strcpy(cap->driver, "cx88_blackbird"); strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | @@ -1368,14 +1368,8 @@ static struct cx8802_driver cx8802_blackbird_driver = { static int __init blackbird_init(void) { - printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx2388x blackbird driver version %s loaded\n", + CX88_VERSION); return cx8802_register_driver(&cx8802_blackbird_driver); } @@ -1389,11 +1383,3 @@ module_exit(blackbird_fini); module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644); MODULE_PARM_DESC(debug,"enable debug messages [video]"); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 27222c9..3929d93 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -28,6 +28,7 @@ #include "cx88.h" #include "tea5767.h" +#include "xc4000.h" static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; @@ -1572,8 +1573,8 @@ static const struct cx88_board cx88_boards[] = { .name = "Pinnacle Hybrid PCTV", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -1610,8 +1611,8 @@ static const struct cx88_board cx88_boards[] = { .name = "Leadtek TV2000 XP Global", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -2042,8 +2043,8 @@ static const struct cx88_board cx88_boards[] = { .name = "Terratec Cinergy HT PCI MKII", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -2081,9 +2082,9 @@ static const struct cx88_board cx88_boards[] = { [CX88_BOARD_WINFAST_DTV1800H] = { .name = "Leadtek WinFast DTV1800 Hybrid", .tuner_type = TUNER_XC2028, - .radio_type = TUNER_XC2028, + .radio_type = UNSET, .tuner_addr = 0x61, - .radio_addr = 0x61, + .radio_addr = ADDR_UNSET, /* * GPIO setting * @@ -2119,6 +2120,99 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_WINFAST_DTV1800H_XC4000] = { + .name = "Leadtek WinFast DTV1800 H (XC4000)", + .tuner_type = TUNER_XC4000, + .radio_type = UNSET, + .tuner_addr = 0x61, + .radio_addr = ADDR_UNSET, + /* + * GPIO setting + * + * 2: mute (0=off,1=on) + * 12: tuner reset pin + * 13: audio source (0=tuner audio,1=line in) + * 14: FM (0=on,1=off ???) + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6040, /* pin 13 = 0, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6000, /* pin 13 = 0, pin 14 = 0 */ + .gpio2 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_WINFAST_DTV2000H_PLUS] = { + .name = "Leadtek WinFast DTV2000 H PLUS", + .tuner_type = TUNER_XC4000, + .radio_type = UNSET, + .tuner_addr = 0x61, + .radio_addr = ADDR_UNSET, + /* + * GPIO + * 2: 1: mute audio + * 12: 0: reset XC4000 + * 13: 1: audio input is line in (0: tuner) + * 14: 0: FM radio + * 16: 0: RF input is cable + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0403, + .gpio1 = 0xF0D7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_CABLE, + .vmux = 0, + .gpio0 = 0x0403, + .gpio1 = 0xF0D7, + .gpio2 = 0x0100, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0403, /* was 0x0407 */ + .gpio1 = 0xF0F7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0403, /* was 0x0407 */ + .gpio1 = 0xF0F7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0403, + .gpio1 = 0xF097, + .gpio2 = 0x0100, + .gpio3 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_PROF_7301] = { .name = "Prof 7301 DVB-S/S2", .tuner_type = UNSET, @@ -2581,6 +2675,15 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x6654, .card = CX88_BOARD_WINFAST_DTV1800H, }, { + /* WinFast DTV1800 H with XC4000 tuner */ + .subvendor = 0x107d, + .subdevice = 0x6f38, + .card = CX88_BOARD_WINFAST_DTV1800H_XC4000, + }, { + .subvendor = 0x107d, + .subdevice = 0x6f42, + .card = CX88_BOARD_WINFAST_DTV2000H_PLUS, + }, { /* PVR2000 PAL Model [107d:6630] */ .subvendor = 0x107d, .subdevice = 0x6630, @@ -2846,6 +2949,23 @@ static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core, return -EINVAL; } +static int cx88_xc4000_winfast2000h_plus_callback(struct cx88_core *core, + int command, int arg) +{ + switch (command) { + case XC4000_TUNER_RESET: + /* GPIO 12 (xc4000 tuner reset) */ + cx_set(MO_GP1_IO, 0x1010); + mdelay(50); + cx_clear(MO_GP1_IO, 0x10); + mdelay(75); + cx_set(MO_GP1_IO, 0x10); + mdelay(75); + return 0; + } + return -EINVAL; +} + /* ------------------------------------------------------------------- */ /* some Divco specific stuff */ static int cx88_pv_8000gt_callback(struct cx88_core *core, @@ -2948,6 +3068,19 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, return -EINVAL; } +static int cx88_xc4000_tuner_callback(struct cx88_core *core, + int command, int arg) +{ + /* Board-specific callbacks */ + switch (core->boardnr) { + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + return cx88_xc4000_winfast2000h_plus_callback(core, + command, arg); + } + return -EINVAL; +} + /* ----------------------------------------------------------------------- */ /* Tuner callback function. Currently only needed for the Pinnacle * * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * @@ -3022,6 +3155,9 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg) case TUNER_XC2028: info_printk(core, "Calling XC2028/3028 callback\n"); return cx88_xc2028_tuner_callback(core, command, arg); + case TUNER_XC4000: + info_printk(core, "Calling XC4000 callback\n"); + return cx88_xc4000_tuner_callback(core, command, arg); case TUNER_XC5000: info_printk(core, "Calling XC5000 callback\n"); return cx88_xc5000_tuner_callback(core, command, arg); @@ -3109,13 +3245,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_WINFAST_DTV1800H: - /* GPIO 12 (xc3028 tuner reset) */ - cx_set(MO_GP1_IO, 0x1010); - mdelay(50); - cx_clear(MO_GP1_IO, 0x10); - mdelay(50); - cx_set(MO_GP1_IO, 0x10); - mdelay(50); + cx88_xc3028_winfast1800h_callback(core, XC2028_TUNER_RESET, 0); + break; + + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + cx88_xc4000_winfast2000h_plus_callback(core, + XC4000_TUNER_RESET, 0); break; case CX88_BOARD_TWINHAN_VP1027_DVBS: diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 2e145f0..fbfdd80 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -759,8 +759,8 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig if (nocomb) value |= (3 << 5); // disable comb filter - cx_write(MO_FILTER_EVEN, value); - cx_write(MO_FILTER_ODD, value); + cx_andor(MO_FILTER_EVEN, 0x7ffc7f, value); /* preserve PEAKEN, PSEL */ + cx_andor(MO_FILTER_ODD, 0x7ffc7f, value); dprintk(1,"set_scale: filter 0x%04x\n", value); return 0; @@ -994,10 +994,10 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) // htotal tmp64 = norm_htotal(norm) * (u64)vdec_clock; do_div(tmp64, fsc8); - htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11); + htotal = (u32)tmp64; dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n", htotal, cx_read(MO_HTOTAL), (u32)tmp64); - cx_write(MO_HTOTAL, htotal); + cx_andor(MO_HTOTAL, 0x07ff, htotal); // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes // the effective vbi offset ~244 samples, the same as the Bt8x8 diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index c69df7e..cf3d33a 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -41,6 +41,7 @@ #include "or51132.h" #include "lgdt330x.h" #include "s5h1409.h" +#include "xc4000.h" #include "xc5000.h" #include "nxt200x.h" #include "cx24123.h" @@ -63,6 +64,7 @@ MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); static unsigned int debug; module_param(debug, int, 0644); @@ -605,6 +607,39 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) return 0; } +static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg) +{ + struct dvb_frontend *fe; + struct videobuf_dvb_frontend *fe0 = NULL; + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + if (!fe0) + return -EINVAL; + + if (!fe0->dvb.frontend) { + printk(KERN_ERR "%s/2: dvb frontend not attached. " + "Can't attach xc4000\n", + dev->core->name); + return -EINVAL; + } + + fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap, + cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc4000 attach failed\n", + dev->core->name); + dvb_frontend_detach(fe0->dvb.frontend); + dvb_unregister_frontend(fe0->dvb.frontend); + fe0->dvb.frontend = NULL; + return -EINVAL; + } + + printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name); + + return 0; +} + static int cx24116_set_ts_param(struct dvb_frontend *fe, int is_punctured) { @@ -1294,7 +1329,25 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; } break; - case CX88_BOARD_GENIATECH_X8000_MT: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &cx88_pinnacle_hybrid_pctv, + &core->i2c_adap); + if (fe0->dvb.frontend) { + struct xc4000_config cfg = { + .i2c_address = 0x61, + .default_pm = 0, + .dvb_amplitude = 134, + .set_smoothedcvbs = 1, + .if_khz = 4560 + }; + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc4000(dev, &cfg) < 0) + goto frontend_detach; + } + break; + case CX88_BOARD_GENIATECH_X8000_MT: dev->ts_gen_cntrl = 0x00; fe0->dvb.frontend = dvb_attach(zl10353_attach, @@ -1577,6 +1630,11 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) udelay(1000); break; + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + /* set RF input to AIR for DVB-T (GPIO 16) */ + cx_write(MO_GP2_IO, 0x0101); + break; + default: err = -ENODEV; } @@ -1692,14 +1750,8 @@ static struct cx8802_driver cx8802_dvb_driver = { static int __init dvb_init(void) { - printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n", + CX88_VERSION); return cx8802_register_driver(&cx8802_dvb_driver); } @@ -1710,10 +1762,3 @@ static void __exit dvb_fini(void) module_init(dvb_init); module_exit(dvb_fini); - -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 3f44200..e614201 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -100,6 +100,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) break; case CX88_BOARD_WINFAST_DTV1000: case CX88_BOARD_WINFAST_DTV1800H: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); auxgpio = gpio; @@ -289,6 +291,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_WINFAST_DTV2000H: case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_WINFAST_DTV1800H: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: ir_codes = RC_MAP_WINFAST; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 1a7b983..cd5386e 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -39,6 +39,7 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.us>"); MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); static unsigned int debug; module_param(debug,int,0644); @@ -613,13 +614,17 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) core->active_type_id != drv->type_id) return -EBUSY; - core->input = 0; - for (i = 0; - i < (sizeof(core->board.input) / sizeof(struct cx88_input)); - i++) { - if (core->board.input[i].type == CX88_VMUX_DVB) { - core->input = i; - break; + if (drv->type_id == CX88_MPEG_DVB) { + /* When switching to DVB, always set the input to the tuner */ + core->last_analog_input = core->input; + core->input = 0; + for (i = 0; + i < (sizeof(core->board.input) / sizeof(struct cx88_input)); + i++) { + if (core->board.input[i].type == CX88_VMUX_DVB) { + core->input = i; + break; + } } } @@ -644,6 +649,12 @@ static int cx8802_request_release(struct cx8802_driver *drv) if (drv->advise_release && --core->active_ref == 0) { + if (drv->type_id == CX88_MPEG_DVB) { + /* If the DVB driver is releasing, reset the input + state to the last configured analog input */ + core->input = core->last_analog_input; + } + drv->advise_release(drv); core->active_type_id = CX88_BOARD_NONE; mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); @@ -890,14 +901,8 @@ static struct pci_driver cx8802_pci_driver = { static int __init cx8802_init(void) { - printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %s loaded\n", + CX88_VERSION); return pci_register_driver(&cx8802_pci_driver); } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index cef4f28..921c56d 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -45,6 +45,7 @@ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(CX88_VERSION); /* ------------------------------------------------------------------ */ @@ -220,7 +221,23 @@ static const struct cx88_ctrl cx8800_ctls[] = { .reg = MO_UV_SATURATION, .mask = 0x00ff, .shift = 0, - },{ + }, { + .v = { + .id = V4L2_CID_SHARPNESS, + .name = "Sharpness", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0x0, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + /* NOTE: the value is converted and written to both even + and odd registers in the code */ + .reg = MO_FILTER_ODD, + .mask = 7 << 7, + .shift = 7, + }, { .v = { .id = V4L2_CID_CHROMA_AGC, .name = "Chroma AGC", @@ -245,6 +262,20 @@ static const struct cx88_ctrl cx8800_ctls[] = { .mask = 1 << 9, .shift = 9, }, { + .v = { + .id = V4L2_CID_BAND_STOP_FILTER, + .name = "Notch filter", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0x0, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = MO_HTOTAL, + .mask = 3 << 11, + .shift = 11, + }, { /* --- audio --- */ .v = { .id = V4L2_CID_AUDIO_MUTE, @@ -300,8 +331,10 @@ const u32 cx88_user_ctrls[] = { V4L2_CID_AUDIO_VOLUME, V4L2_CID_AUDIO_BALANCE, V4L2_CID_AUDIO_MUTE, + V4L2_CID_SHARPNESS, V4L2_CID_CHROMA_AGC, V4L2_CID_COLOR_KILLER, + V4L2_CID_BAND_STOP_FILTER, 0 }; EXPORT_SYMBOL(cx88_user_ctrls); @@ -962,6 +995,10 @@ int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) case V4L2_CID_AUDIO_VOLUME: ctl->value = 0x3f - (value & 0x3f); break; + case V4L2_CID_SHARPNESS: + ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1) + : 0); + break; default: ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; break; @@ -1039,6 +1076,12 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) } mask=0xffff; break; + case V4L2_CID_SHARPNESS: + /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ + value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7)); + /* needs to be set for both fields */ + cx_andor(MO_FILTER_EVEN, mask, value); + break; case V4L2_CID_CHROMA_AGC: /* Do not allow chroma AGC to be enabled for SECAM */ value = ((ctl->value - c->off) << c->shift) & c->mask; @@ -1161,7 +1204,6 @@ static int vidioc_querycap (struct file *file, void *priv, strcpy(cap->driver, "cx8800"); strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | @@ -1480,7 +1522,6 @@ static int radio_querycap (struct file *file, void *priv, strcpy(cap->driver, "cx8800"); strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } @@ -2139,14 +2180,8 @@ static struct pci_driver cx8800_pci_driver = { static int __init cx8800_init(void) { - printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %s loaded\n", + CX88_VERSION); return pci_register_driver(&cx8800_pci_driver); } @@ -2157,11 +2192,3 @@ static void __exit cx8800_fini(void) module_init(cx8800_init); module_exit(cx8800_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index a399a8b..fa8d307 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -39,9 +39,9 @@ #include "cx88-reg.h" #include "tuner-xc2028.h" -#include <linux/version.h> #include <linux/mutex.h> -#define CX88_VERSION_CODE KERNEL_VERSION(0, 0, 8) + +#define CX88_VERSION "0.0.9" #define UNSET (-1U) @@ -242,6 +242,8 @@ extern const struct sram_channel const cx88_sram_channels[]; #define CX88_BOARD_SAMSUNG_SMT_7020 84 #define CX88_BOARD_TWINHAN_VP1027_DVBS 85 #define CX88_BOARD_TEVII_S464 86 +#define CX88_BOARD_WINFAST_DTV2000H_PLUS 87 +#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -375,6 +377,7 @@ struct cx88_core { u32 audiomode_manual; u32 audiomode_current; u32 input; + u32 last_analog_input; u32 astat; u32 use_nicam; unsigned long last_change; diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig index 6b19540..60a456e 100644 --- a/drivers/media/video/davinci/Kconfig +++ b/drivers/media/video/davinci/Kconfig @@ -91,3 +91,26 @@ config VIDEO_ISIF To compile this driver as a module, choose M here: the module will be called vpfe. + +config VIDEO_DM644X_VPBE + tristate "DM644X VPBE HW module" + depends on ARCH_DAVINCI_DM644x + select VIDEO_VPSS_SYSTEM + select VIDEOBUF_DMA_CONTIG + help + Enables VPBE modules used for display on a DM644x + SoC. + + To compile this driver as a module, choose M here: the + module will be called vpbe. + + +config VIDEO_VPBE_DISPLAY + tristate "VPBE V4L2 Display driver" + depends on ARCH_DAVINCI_DM644x + select VIDEO_DM644X_VPBE + help + Enables VPBE V4L2 Display driver on a DM644x device + + To compile this driver as a module, choose M here: the + module will be called vpbe_display. diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index a379557..ae7dafb 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o obj-$(CONFIG_VIDEO_ISIF) += isif.o +obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o +obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c index c29ac88..bd443ee 100644 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ b/drivers/media/video/davinci/dm355_ccdc.c @@ -39,6 +39,7 @@ #include <linux/videodev2.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/module.h> #include <media/davinci/dm355_ccdc.h> #include <media/davinci/vpss.h> diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c index c8b32c1..8051c29 100644 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ b/drivers/media/video/davinci/dm644x_ccdc.c @@ -40,6 +40,7 @@ #include <linux/gfp.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/module.h> #include <media/davinci/dm644x_ccdc.h> #include <media/davinci/vpss.h> diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index 9f3bfc1..af96802 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c @@ -422,7 +422,7 @@ static int __init vpif_probe(struct platform_device *pdev) if (!res) return -ENOENT; - res_len = res->end - res->start + 1; + res_len = resource_size(res); res = request_mem_region(res->start, res_len, res->name); if (!res) diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index d93ad74..49e4deb 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -33,7 +33,6 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/version.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> @@ -44,6 +43,7 @@ MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VPIF_CAPTURE_VERSION); #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) #define vpif_dbg(level, debug, fmt, arg...) \ @@ -1677,7 +1677,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_capture_config *config = vpif_dev->platform_data; - cap->version = VPIF_CAPTURE_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); @@ -2211,10 +2210,8 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFCapture_DRIVER_V%d.%d.%d", - (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff, - (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff, - (VPIF_CAPTURE_VERSION_CODE) & 0xff); + "DM646x_VPIFCapture_DRIVER_V%s", + VPIF_CAPTURE_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; } diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h index 7a4196d..064550f 100644 --- a/drivers/media/video/davinci/vpif_capture.h +++ b/drivers/media/video/davinci/vpif_capture.h @@ -23,7 +23,6 @@ /* Header files */ #include <linux/videodev2.h> -#include <linux/version.h> #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/videobuf-core.h> @@ -33,11 +32,7 @@ #include "vpif.h" /* Macros */ -#define VPIF_MAJOR_RELEASE 0 -#define VPIF_MINOR_RELEASE 0 -#define VPIF_BUILD 1 -#define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \ - (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) +#define VPIF_CAPTURE_VERSION "0.0.2" #define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ (V4L2_FIELD_NONE == field)) || \ diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index cdf659a..286f029 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -29,7 +29,6 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/version.h> #include <linux/slab.h> #include <asm/irq.h> @@ -47,6 +46,7 @@ MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VPIF_DISPLAY_VERSION); #define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) @@ -701,7 +701,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_display_config *config = vpif_dev->platform_data; - cap->version = VPIF_DISPLAY_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); @@ -1740,10 +1739,8 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d", - (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff, - (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff, - (VPIF_DISPLAY_VERSION_CODE) & 0xff); + "DM646x_VPIFDisplay_DRIVER_V%s", + VPIF_DISPLAY_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h index b53aaa8..5d1936d 100644 --- a/drivers/media/video/davinci/vpif_display.h +++ b/drivers/media/video/davinci/vpif_display.h @@ -18,7 +18,6 @@ /* Header files */ #include <linux/videodev2.h> -#include <linux/version.h> #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/videobuf-core.h> @@ -27,12 +26,7 @@ #include "vpif.h" /* Macros */ -#define VPIF_MAJOR_RELEASE (0) -#define VPIF_MINOR_RELEASE (0) -#define VPIF_BUILD (1) - -#define VPIF_DISPLAY_VERSION_CODE \ - ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) +#define VPIF_DISPLAY_VERSION "0.0.2" #define VPIF_VALID_FIELD(field) \ (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 3cb78f2..f6f622e 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -3,7 +3,6 @@ config VIDEO_EM28XX depends on VIDEO_DEV && I2C select VIDEO_TUNER select VIDEO_TVEEPROM - depends on RC_CORE select VIDEOBUF_VMALLOC select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO @@ -40,7 +39,20 @@ config VIDEO_EM28XX_DVB select DVB_S921 if !DVB_FE_CUSTOMISE select DVB_DRXD if !DVB_FE_CUSTOMISE select DVB_CXD2820R if !DVB_FE_CUSTOMISE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE + select DVB_TDA10071 if !DVB_FE_CUSTOMISE + select DVB_A8293 if !DVB_FE_CUSTOMISE select VIDEOBUF_DVB ---help--- This adds support for DVB cards based on the Empiatech em28xx chips. + +config VIDEO_EM28XX_RC + bool "EM28XX Remote Controller support" + depends on RC_CORE + depends on VIDEO_EM28XX + depends on !(RC_CORE=m && VIDEO_EM28XX=y) + default y + ---help--- + Enables Remote Controller support on em28xx driver. diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index d0f093d..2abdf76 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -1,5 +1,7 @@ -em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ - em28xx-input.o em28xx-vbi.o +em28xx-y := em28xx-video.o em28xx-i2c.o em28xx-cards.o +em28xx-y += em28xx-core.o em28xx-vbi.o + +em28xx-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-input.o em28xx-alsa-objs := em28xx-audio.o @@ -7,8 +9,8 @@ obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 3c48a72..cff0768 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -3,9 +3,9 @@ * * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> * - * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org> + * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com> * - Port to work with the in-kernel driver - * - Several cleanups + * - Cleanups, fixes, alsa-controls, etc. * * This driver is based on my previous au600 usb pstn audio driver * and inherits all the copyrights @@ -41,6 +41,7 @@ #include <sound/info.h> #include <sound/initval.h> #include <sound/control.h> +#include <sound/tlv.h> #include <media/v4l2-common.h> #include "em28xx.h" @@ -212,9 +213,12 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { + em28xx_errdev("submit of audio urb failed\n"); em28xx_deinit_isoc_audio(dev); + atomic_set(&dev->stream_started, 0); return errCode; } + } return 0; @@ -245,6 +249,7 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, @@ -276,24 +281,27 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) return -ENODEV; } - /* Sets volume, mute, etc */ + runtime->hw = snd_em28xx_hw_capture; + if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) { + if (dev->audio_ifnum) + dev->alt = 1; + else + dev->alt = 7; - dev->mute = 0; - mutex_lock(&dev->lock); - ret = em28xx_audio_analog_set(dev); - if (ret < 0) - goto err; + dprintk("changing alternate number on interface %d to %d\n", + dev->audio_ifnum, dev->alt); + usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt); - runtime->hw = snd_em28xx_hw_capture; - if (dev->alt == 0 && dev->adev.users == 0) { - int errCode; - dev->alt = 7; - dprintk("changing alternate number to 7\n"); - errCode = usb_set_interface(dev->udev, 0, 7); - } + /* Sets volume, mute, etc */ + dev->mute = 0; + mutex_lock(&dev->lock); + ret = em28xx_audio_analog_set(dev); + if (ret < 0) + goto err; - dev->adev.users++; - mutex_unlock(&dev->lock); + dev->adev.users++; + mutex_unlock(&dev->lock); + } snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); dev->adev.capture_pcm_substream = substream; @@ -342,6 +350,8 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, ret = snd_pcm_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); + if (ret < 0) + return ret; format = params_format(hw_params); rate = params_rate(hw_params); channels = params_channels(hw_params); @@ -393,20 +403,24 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct em28xx *dev = snd_pcm_substream_chip(substream); - int retval; + int retval = 0; switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ + case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: atomic_set(&dev->stream_started, 1); break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ + case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&dev->stream_started, 1); + atomic_set(&dev->stream_started, 0); break; default: retval = -EINVAL; } schedule_work(&dev->wq_trigger); - return 0; + return retval; } static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream @@ -432,6 +446,179 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, return vmalloc_to_page(pageptr); } +/* + * AC97 volume control support + */ +static int em28xx_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0; + info->value.integer.max = 0x1f; + + return 0; +} + +static int em28xx_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) | + (0x1f - (value->value.integer.value[1] & 0x1f)) << 8; + int rc; + + mutex_lock(&dev->lock); + rc = em28xx_read_ac97(dev, kcontrol->private_value); + if (rc < 0) + goto err; + + val |= rc & 0x8000; /* Preserve the mute flag */ + + rc = em28xx_write_ac97(dev, kcontrol->private_value, val); + if (rc < 0) + goto err; + + dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int em28xx_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + int val; + + mutex_lock(&dev->lock); + val = em28xx_read_ac97(dev, kcontrol->private_value); + mutex_unlock(&dev->lock); + if (val < 0) + return val; + + dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + + value->value.integer.value[0] = 0x1f - (val & 0x1f); + value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f); + + return 0; +} + +static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + u16 val = value->value.integer.value[0]; + int rc; + + mutex_lock(&dev->lock); + rc = em28xx_read_ac97(dev, kcontrol->private_value); + if (rc < 0) + goto err; + + if (val) + rc &= 0x1f1f; + else + rc |= 0x8000; + + rc = em28xx_write_ac97(dev, kcontrol->private_value, rc); + if (rc < 0) + goto err; + + dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + int val; + + mutex_lock(&dev->lock); + val = em28xx_read_ac97(dev, kcontrol->private_value); + mutex_unlock(&dev->lock); + if (val < 0) + return val; + + if (val & 0x8000) + value->value.integer.value[0] = 0; + else + value->value.integer.value[0] = 1; + + dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0); + +static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev, + char *name, int id) +{ + int err; + char ctl_name[44]; + struct snd_kcontrol *kctl; + struct snd_kcontrol_new tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + tmp.private_value = id, + tmp.name = ctl_name, + + /* Add Mute Control */ + sprintf(ctl_name, "%s Switch", name); + tmp.get = em28xx_vol_get_mute; + tmp.put = em28xx_vol_put_mute; + tmp.info = snd_ctl_boolean_mono_info; + kctl = snd_ctl_new1(&tmp, dev); + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + dprintk("Added control %s for ac97 volume control 0x%04x\n", + ctl_name, id); + + memset (&tmp, 0, sizeof(tmp)); + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + tmp.private_value = id, + tmp.name = ctl_name, + + /* Add Volume Control */ + sprintf(ctl_name, "%s Volume", name); + tmp.get = em28xx_vol_get; + tmp.put = em28xx_vol_put; + tmp.info = em28xx_vol_info; + tmp.tlv.p = em28xx_db_scale, + kctl = snd_ctl_new1(&tmp, dev); + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + dprintk("Added control %s for ac97 volume control 0x%04x\n", + ctl_name, id); + + return 0; +} + +/* + * register/unregister code and data + */ static struct snd_pcm_ops snd_em28xx_pcm_capture = { .open = snd_em28xx_capture_open, .close = snd_em28xx_pcm_close, @@ -452,17 +639,17 @@ static int em28xx_audio_init(struct em28xx *dev) static int devnr; int err; - if (dev->has_alsa_audio != 1) { + if (!dev->has_alsa_audio || dev->audio_ifnum < 0) { /* This device does not support the extension (in this case the device is expecting the snd-usb-audio module or doesn't have analog audio support at all) */ return 0; } - printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " - "non standard usbaudio\n"); + printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n"); printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " "Rechberger\n"); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n"); err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, &card); @@ -488,6 +675,22 @@ static int em28xx_audio_init(struct em28xx *dev) INIT_WORK(&dev->wq_trigger, audio_trigger); + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL); + em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL); + em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL); + em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL); + em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL); + em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL); + em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL); + + em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL); + em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL); + em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL); + em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL); + em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL); + } + err = snd_card_register(card); if (err < 0) { snd_card_free(card); @@ -538,7 +741,7 @@ static void __exit em28xx_alsa_unregister(void) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); MODULE_DESCRIPTION("Em28xx Audio driver"); module_init(em28xx_alsa_register); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4e37375..9b747c2 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -60,7 +60,7 @@ static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); -/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ +/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */ static unsigned long em28xx_devused; struct em28xx_hash_table { @@ -289,7 +289,7 @@ static struct em28xx_reg_seq leadership_reset[] = { { -1, -1, -1, -1}, }; -/* 2013:024f PCTV Systems nanoStick T2 290e +/* 2013:024f PCTV nanoStick T2 290e * GPIO_6 - demod reset * GPIO_7 - LED */ @@ -300,6 +300,42 @@ static struct em28xx_reg_seq pctv_290e[] = { {-1, -1, -1, -1}, }; +#if 0 +static struct em28xx_reg_seq terratec_h5_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + {EM2874_R80_GPIO, 0xf2, 0xff, 50}, + {EM2874_R80_GPIO, 0xf6, 0xff, 50}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_h5_digital[] = { + {EM2874_R80_GPIO, 0xf6, 0xff, 10}, + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + {EM2874_R80_GPIO, 0xa6, 0xff, 10}, + { -1, -1, -1, -1}, +}; +#endif + +/* 2013:024f PCTV DVB-S2 Stick 460e + * GPIO_0 - POWER_ON + * GPIO_1 - BOOST + * GPIO_2 - VUV_LNB (red LED) + * GPIO_3 - EXT_12V + * GPIO_4 - INT_DEM (DEMOD GPIO_0) + * GPIO_5 - INT_LNB + * GPIO_6 - RESET_DEM + * GPIO_7 - LED (green LED) + */ +static struct em28xx_reg_seq pctv_460e[] = { + {EM2874_R80_GPIO, 0x01, 0xff, 50}, + {0x0d, 0xff, 0xff, 50}, + {EM2874_R80_GPIO, 0x41, 0xff, 50}, /* GPIO_6=1 */ + {0x0d, 0x42, 0xff, 50}, + {EM2874_R80_GPIO, 0x61, 0xff, 50}, /* GPIO_5=1 */ + { -1, -1, -1, -1}, +}; + /* * Board definitions */ @@ -843,6 +879,19 @@ struct em28xx_board em28xx_boards[] = { .gpio = terratec_cinergy_USB_XS_FR_analog, } }, }, + [EM2884_BOARD_TERRATEC_H5] = { + .name = "Terratec Cinergy H5", + .has_dvb = 1, +#if 0 + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x41, + .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */ + .tuner_gpio = terratec_h5_gpio, +#endif + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { .name = "Hauppauge WinTV HVR 900", .tda9887_conf = TDA9887_PRESENT, @@ -1259,7 +1308,7 @@ struct em28xx_board em28xx_boards[] = { } }, }, - [EM2874_LEADERSHIP_ISDBT] = { + [EM2874_BOARD_LEADERSHIP_ISDBT] = { .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, @@ -1319,7 +1368,6 @@ struct em28xx_board em28xx_boards[] = { }, [EM2880_BOARD_KWORLD_DVB_305U] = { .name = "KWorld DVB-T 305U", - .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, @@ -1770,16 +1818,27 @@ struct em28xx_board em28xx_boards[] = { .dvb_gpio = kworld_a340_digital, .tuner_gpio = default_tuner_gpio, }, - /* 2013:024f PCTV Systems nanoStick T2 290e. + /* 2013:024f PCTV nanoStick T2 290e. * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */ [EM28174_BOARD_PCTV_290E] = { + .name = "PCTV nanoStick T2 290e", .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .name = "PCTV Systems nanoStick T2 290e", .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_290e, .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + }, + /* 2013:024f PCTV DVB-S2 Stick 460e + * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */ + [EM28174_BOARD_PCTV_460E] = { + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .name = "PCTV DVB-S2 Stick (460e)", + .tuner_type = TUNER_ABSENT, + .tuner_gpio = pctv_460e, + .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1855,13 +1914,17 @@ struct usb_device_id em28xx_id_table[] = { { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0043), - .driver_info = EM2870_BOARD_TERRATEC_XS }, - { USB_DEVICE(0x0ccd, 0x0047), + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x10a2), /* Rev. 1 */ + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x10ad), /* Rev. 2 */ .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { USB_DEVICE(0x0ccd, 0x0084), .driver_info = EM2860_BOARD_TERRATEC_AV350 }, { USB_DEVICE(0x0ccd, 0x0096), .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, + { USB_DEVICE(0x0ccd, 0x10AF), + .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x0fd9, 0x0033), .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, { USB_DEVICE(0x185b, 0x2870), @@ -1910,6 +1973,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_KWORLD_A340 }, { USB_DEVICE(0x2013, 0x024f), .driver_info = EM28174_BOARD_PCTV_290E }, + { USB_DEVICE(0x2013, 0x024c), + .driver_info = EM28174_BOARD_PCTV_460E }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -1937,7 +2002,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { {0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT}, {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC}, {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, - {0x6b800080, EM2874_LEADERSHIP_ISDBT, TUNER_ABSENT}, + {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT}, }; /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ @@ -2660,10 +2725,9 @@ void em28xx_card_setup(struct em28xx *dev) .addr = 0xba >> 1, .platform_data = &pdata, }; - struct v4l2_subdev *sd; pdata.xtal = dev->sensor_xtal; - sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, &mt9v011_info, NULL); } @@ -2738,9 +2802,9 @@ static void flush_request_modules(struct em28xx *dev) #endif /* CONFIG_MODULES */ /* - * em28xx_realease_resources() + * em28xx_release_resources() * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload + * called when the device gets disconnected or at module unload */ void em28xx_release_resources(struct em28xx *dev) { @@ -2754,8 +2818,6 @@ void em28xx_release_resources(struct em28xx *dev) em28xx_release_analog_resources(dev); - em28xx_remove_from_devlist(dev); - em28xx_i2c_unregister(dev); v4l2_device_unregister(&dev->v4l2_dev); @@ -2763,7 +2825,7 @@ void em28xx_release_resources(struct em28xx *dev) usb_put_dev(dev->udev); /* Mark device as unused */ - em28xx_devused &= ~(1 << dev->devno); + clear_bit(dev->devno, &em28xx_devused); }; /* @@ -2776,7 +2838,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, { struct em28xx *dev = *devhandle; int retval; - int errCode; dev->udev = udev; mutex_init(&dev->ctrl_urb_lock); @@ -2842,11 +2903,25 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_info("chip ID is em2882/em2883\n"); dev->wait_after_write = 0; break; + case CHIP_ID_EM2884: + em28xx_info("chip ID is em2884\n"); + dev->reg_gpio_num = EM2874_R80_GPIO; + dev->wait_after_write = 0; + break; default: em28xx_info("em28xx chip ID = %d\n", dev->chip_id); } } + if (dev->is_audio_only) { + retval = em28xx_audio_setup(dev); + if (retval) + return -ENODEV; + em28xx_init_extension(dev); + + return 0; + } + /* Prepopulate cached GPO register content */ retval = em28xx_read_reg(dev, dev->reg_gpo_num); if (retval >= 0) @@ -2858,7 +2933,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, /* Resets I2C speed */ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { - em28xx_errdev("%s: em28xx_write_regs_req failed!" + em28xx_errdev("%s: em28xx_write_reg failed!" " retval [%d]\n", __func__, retval); return retval; @@ -2872,12 +2947,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } /* register i2c bus */ - errCode = em28xx_i2c_register(dev); - if (errCode < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n", - __func__, errCode); - return errCode; + retval = em28xx_i2c_register(dev); + if (retval < 0) { + em28xx_errdev("%s: em28xx_i2c_register - error [%d]!\n", + __func__, retval); + goto unregister_dev; } /* @@ -2891,11 +2965,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_card_setup(dev); /* Configure audio */ - errCode = em28xx_audio_setup(dev); - if (errCode < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", - __func__, errCode); + retval = em28xx_audio_setup(dev); + if (retval < 0) { + em28xx_errdev("%s: Error while setting audio - error [%d]!\n", + __func__, retval); + goto fail; } /* wake i2c devices */ @@ -2909,44 +2983,47 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (dev->board.has_msp34xx) { /* Send a reset to other chips via gpio */ - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - " - "msp34xx(1) failed! errCode [%d]\n", - __func__, errCode); - return errCode; + retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); + if (retval < 0) { + em28xx_errdev("%s: em28xx_write_reg - " + "msp34xx(1) failed! error [%d]\n", + __func__, retval); + goto fail; } msleep(3); - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - " - "msp34xx(2) failed! errCode [%d]\n", - __func__, errCode); - return errCode; + retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); + if (retval < 0) { + em28xx_errdev("%s: em28xx_write_reg - " + "msp34xx(2) failed! error [%d]\n", + __func__, retval); + goto fail; } msleep(3); } - em28xx_add_into_devlist(dev); - retval = em28xx_register_analog_devices(dev); if (retval < 0) { - em28xx_release_resources(dev); - goto fail_reg_devices; + goto fail; } - em28xx_init_extension(dev); - /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); return 0; -fail_reg_devices: +fail: + em28xx_i2c_unregister(dev); + +unregister_dev: + v4l2_device_unregister(&dev->v4l2_dev); + return retval; } +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) + /* * em28xx_usb_probe() * checks for supported devices @@ -2956,19 +3033,27 @@ static int em28xx_usb_probe(struct usb_interface *interface, { const struct usb_endpoint_descriptor *endpoint; struct usb_device *udev; - struct usb_interface *uif; struct em28xx *dev = NULL; int retval; - int i, nr, ifnum, isoc_pipe; + bool is_audio_only = false, has_audio = false; + int i, nr, isoc_pipe; + const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; char *speed; char descr[255] = ""; udev = usb_get_dev(interface_to_usbdev(interface)); - ifnum = interface->altsetting[0].desc.bInterfaceNumber; /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); - em28xx_devused |= 1<<nr; + do { + nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); + if (nr >= EM28XX_MAXBOARDS) { + /* No free device slots */ + printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", + EM28XX_MAXBOARDS); + retval = -ENOMEM; + goto err_no_slot; + } + } while (test_and_set_bit(nr, &em28xx_devused)); /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { @@ -2979,11 +3064,23 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum, interface->altsetting[0].desc.bInterfaceClass); - em28xx_devused &= ~(1<<nr); retval = -ENODEV; goto err; } + /* Get endpoints */ + for (i = 0; i < interface->num_altsetting; i++) { + int ep; + + for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + e = &interface->altsetting[i].endpoint[ep]; + + if (e->desc.bEndpointAddress == 0x83) + has_audio = true; + } + } + endpoint = &interface->cur_altsetting->endpoint[0].desc; /* check if the device has the iso in endpoint at the correct place */ @@ -3003,19 +3100,21 @@ static int em28xx_usb_probe(struct usb_interface *interface, check_interface = 0; if (!check_interface) { - em28xx_err(DRIVER_NAME " video device (%04x:%04x): " - "interface %i, class %i found.\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - em28xx_err(DRIVER_NAME " This is an anciliary " - "interface not used by the driver\n"); - - em28xx_devused &= ~(1<<nr); - retval = -ENODEV; - goto err; + if (has_audio) { + is_audio_only = true; + } else { + em28xx_err(DRIVER_NAME " video device (%04x:%04x): " + "interface %i, class %i found.\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + em28xx_err(DRIVER_NAME " This is an anciliary " + "interface not used by the driver\n"); + + retval = -ENODEV; + goto err; + } } } @@ -3045,8 +3144,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (*descr) strlcat(descr, " ", sizeof(descr)); - printk(DRIVER_NAME ": New device %s@ %s Mbps " - "(%04x:%04x, interface %d, class %d)\n", + printk(KERN_INFO DRIVER_NAME + ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n", descr, speed, le16_to_cpu(udev->descriptor.idVendor), @@ -3054,6 +3153,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum, interface->altsetting->desc.bInterfaceNumber); + if (has_audio) + printk(KERN_INFO DRIVER_NAME + ": Audio Vendor Class interface %i found\n", + ifnum); + /* * Make sure we have 480 Mbps of bandwidth, otherwise things like * video stream wouldn't likely work, since 12 Mbps is generally @@ -3063,36 +3167,29 @@ static int em28xx_usb_probe(struct usb_interface *interface, printk(DRIVER_NAME ": Device initialization failed.\n"); printk(DRIVER_NAME ": Device must be connected to a high-speed" " USB 2.0 port.\n"); - em28xx_devused &= ~(1<<nr); retval = -ENODEV; goto err; } - if (nr >= EM28XX_MAXBOARDS) { - printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", - EM28XX_MAXBOARDS); - em28xx_devused &= ~(1<<nr); - retval = -ENOMEM; - goto err; - } - /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { em28xx_err(DRIVER_NAME ": out of memory!\n"); - em28xx_devused &= ~(1<<nr); retval = -ENOMEM; goto err; } - snprintf(dev->name, 29, "em28xx #%d", nr); + snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr); dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; + dev->is_audio_only = is_audio_only; + dev->has_alsa_audio = has_audio; + dev->audio_ifnum = ifnum; /* Checks if audio is provided by some interface */ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { - uif = udev->config->interface[i]; + struct usb_interface *uif = udev->config->interface[i]; if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { dev->has_audio_class = 1; break; @@ -3100,42 +3197,43 @@ static int em28xx_usb_probe(struct usb_interface *interface, } /* compute alternate max packet sizes */ - uif = udev->actconfig->interface[0]; - - dev->num_alt = uif->num_altsetting; + dev->num_alt = interface->num_altsetting; dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); if (dev->alt_max_pkt_size == NULL) { em28xx_errdev("out of memory!\n"); - em28xx_devused &= ~(1<<nr); kfree(dev); retval = -ENOMEM; goto err; } for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); - dev->alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); + unsigned int size = tmp & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(tmp); + + dev->alt_max_pkt_size[i] = size; } if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) dev->model = card[nr]; + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + /* allocate device struct */ mutex_init(&dev->lock); mutex_lock(&dev->lock); retval = em28xx_init_dev(&dev, udev, interface, nr); if (retval) { - em28xx_devused &= ~(1<<dev->devno); mutex_unlock(&dev->lock); + kfree(dev->alt_max_pkt_size); kfree(dev); goto err; } - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - request_modules(dev); /* Should be the last thing to do, to avoid newer udev's to @@ -3143,15 +3241,26 @@ static int em28xx_usb_probe(struct usb_interface *interface, */ mutex_unlock(&dev->lock); + /* + * These extensions can be modules. If the modules are already + * loaded then we can initialise the device now, otherwise we + * will initialise it when the modules load instead. + */ + em28xx_init_extension(dev); + return 0; err: + clear_bit(nr, &em28xx_devused); + +err_no_slot: + usb_put_dev(udev); return retval; } /* * em28xx_usb_disconnect() - * called when the device gets diconencted + * called when the device gets disconnected * video device will be unregistered on v4l2_close in case it is still open */ static void em28xx_usb_disconnect(struct usb_interface *interface) @@ -3164,6 +3273,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) if (!dev) return; + if (dev->is_audio_only) { + mutex_lock(&dev->lock); + em28xx_close_extension(dev); + mutex_unlock(&dev->lock); + return; + } + em28xx_info("disconnecting %s\n", dev->vdev->name); flush_request_modules(dev); @@ -3192,10 +3308,10 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_release_resources(dev); } - em28xx_close_extension(dev); - mutex_unlock(&dev->lock); + em28xx_close_extension(dev); + if (!dev->users) { kfree(dev->alt_max_pkt_size); kfree(dev); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index e33f145..804a4ab 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -211,6 +211,7 @@ int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) { return em28xx_write_regs(dev, reg, &val, 1); } +EXPORT_SYMBOL_GPL(em28xx_write_reg); /* * em28xx_write_reg_bits() @@ -286,6 +287,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg) return ret; return le16_to_cpu(val); } +EXPORT_SYMBOL_GPL(em28xx_read_ac97); /* * em28xx_write_ac97() @@ -313,13 +315,14 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) return 0; } +EXPORT_SYMBOL_GPL(em28xx_write_ac97); -struct em28xx_vol_table { +struct em28xx_vol_itable { enum em28xx_amux mux; u8 reg; }; -static struct em28xx_vol_table inputs[] = { +static struct em28xx_vol_itable inputs[] = { { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, @@ -403,7 +406,12 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } -static const struct em28xx_vol_table outputs[] = { +struct em28xx_vol_otable { + enum em28xx_aout mux; + u8 reg; +}; + +static const struct em28xx_vol_otable outputs[] = { { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, @@ -492,17 +500,13 @@ int em28xx_audio_setup(struct em28xx *dev) if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { /* Digital only device - don't load any alsa module */ - dev->audio_mode.has_audio = 0; - dev->has_audio_class = 0; - dev->has_alsa_audio = 0; + dev->audio_mode.has_audio = false; + dev->has_audio_class = false; + dev->has_alsa_audio = false; return 0; } - /* If device doesn't support Usb Audio Class, use vendor class */ - if (!dev->has_audio_class) - dev->has_alsa_audio = 1; - - dev->audio_mode.has_audio = 1; + dev->audio_mode.has_audio = true; /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); @@ -512,8 +516,8 @@ int em28xx_audio_setup(struct em28xx *dev) cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { /* The device doesn't have vendor audio at all */ - dev->has_alsa_audio = 0; - dev->audio_mode.has_audio = 0; + dev->has_alsa_audio = false; + dev->audio_mode.has_audio = false; return 0; } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == EM28XX_CHIPCFG_I2S_3_SAMPRATES) { @@ -542,8 +546,8 @@ int em28xx_audio_setup(struct em28xx *dev) */ em28xx_warn("AC97 chip type couldn't be determined\n"); dev->audio_mode.ac97 = EM28XX_NO_AC97; - dev->has_alsa_audio = 0; - dev->audio_mode.has_audio = 0; + dev->has_alsa_audio = false; + dev->audio_mode.has_audio = false; goto init_audio; } @@ -615,7 +619,9 @@ int em28xx_capture_start(struct em28xx *dev, int start) { int rc; - if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { + if (dev->chip_id == CHIP_ID_EM2874 || + dev->chip_id == CHIP_ID_EM2884 || + dev->chip_id == CHIP_ID_EM28174) { /* The Transport Stream Enable Register moved in em2874 */ if (!start) { rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, @@ -884,6 +890,7 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) } return rc; } +EXPORT_SYMBOL_GPL(em28xx_gpio_set); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) { @@ -917,7 +924,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode); static void em28xx_irq_callback(struct urb *urb) { struct em28xx *dev = urb->context; - int rc, i; + int i; switch (urb->status) { case 0: /* success */ @@ -934,7 +941,7 @@ static void em28xx_irq_callback(struct urb *urb) /* Copy data from URB */ spin_lock(&dev->slock); - rc = dev->isoc_ctl.isoc_copy(dev, urb); + dev->isoc_ctl.isoc_copy(dev, urb); spin_unlock(&dev->slock); /* Reset urb buffers */ @@ -1106,17 +1113,19 @@ EXPORT_SYMBOL_GPL(em28xx_init_isoc); int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) { unsigned int chip_cfg2; - unsigned int packet_size = 564; - - if (dev->chip_id == CHIP_ID_EM2874) { - /* FIXME - for now assume 564 like it was before, but the - em2874 code should be added to return the proper value... */ - packet_size = 564; - } else if (dev->chip_id == CHIP_ID_EM28174) { - /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T - but too much for 44 Mbit DVB-C. */ - packet_size = 752; - } else { + unsigned int packet_size; + + switch (dev->chip_id) { + case CHIP_ID_EM2710: + case CHIP_ID_EM2750: + case CHIP_ID_EM2800: + case CHIP_ID_EM2820: + case CHIP_ID_EM2840: + case CHIP_ID_EM2860: + /* No DVB support */ + return -EINVAL; + case CHIP_ID_EM2870: + case CHIP_ID_EM2883: /* TS max packet size stored in bits 1-0 of R01 */ chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { @@ -1133,9 +1142,24 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) packet_size = 752; break; } + break; + case CHIP_ID_EM2874: + /* + * FIXME: for now assumes 564 like it was before, but the + * em2874 code should be added to return the proper value + */ + packet_size = 564; + break; + case CHIP_ID_EM2884: + case CHIP_ID_EM28174: + default: + /* + * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T + * but not enough for 44 Mbit DVB-C. + */ + packet_size = 752; } - em28xx_coredbg("dvb max packet size=%d\n", packet_size); return packet_size; } EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); @@ -1160,25 +1184,6 @@ static LIST_HEAD(em28xx_devlist); static DEFINE_MUTEX(em28xx_devlist_mutex); /* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void em28xx_remove_from_devlist(struct em28xx *dev) -{ - mutex_lock(&em28xx_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&em28xx_devlist_mutex); -}; - -void em28xx_add_into_devlist(struct em28xx *dev) -{ - mutex_lock(&em28xx_devlist_mutex); - list_add_tail(&dev->devlist, &em28xx_devlist); - mutex_unlock(&em28xx_devlist_mutex); -}; - -/* * Extension interface */ @@ -1193,8 +1198,8 @@ int em28xx_register_extension(struct em28xx_ops *ops) list_for_each_entry(dev, &em28xx_devlist, devlist) { ops->init(dev); } - printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); mutex_unlock(&em28xx_devlist_mutex); + printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); return 0; } EXPORT_SYMBOL(em28xx_register_extension); @@ -1207,36 +1212,34 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) list_for_each_entry(dev, &em28xx_devlist, devlist) { ops->fini(dev); } - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); + printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); } EXPORT_SYMBOL(em28xx_unregister_extension); void em28xx_init_extension(struct em28xx *dev) { - struct em28xx_ops *ops = NULL; + const struct em28xx_ops *ops = NULL; mutex_lock(&em28xx_devlist_mutex); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->init) - ops->init(dev); - } + list_add_tail(&dev->devlist, &em28xx_devlist); + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->init) + ops->init(dev); } mutex_unlock(&em28xx_devlist_mutex); } void em28xx_close_extension(struct em28xx *dev) { - struct em28xx_ops *ops = NULL; + const struct em28xx_ops *ops = NULL; mutex_lock(&em28xx_devlist_mutex); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->fini) - ops->fini(dev); - } + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); } + list_del(&dev->devlist); mutex_unlock(&em28xx_devlist_mutex); } diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 7904ca4..cef7a2d 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -1,7 +1,7 @@ /* DVB device driver for em28xx - (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org> + (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org> (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> - Fixes for the driver to properly work with HVR-950 @@ -40,6 +40,10 @@ #include "s921.h" #include "drxd.h" #include "cxd2820r.h" +#include "tda18271c2dd.h" +#include "drxk.h" +#include "tda10071.h" +#include "a8293.h" MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); @@ -73,6 +77,11 @@ struct em28xx_dvb { struct dmx_frontend fe_hw; struct dmx_frontend fe_mem; struct dvb_net net; + + /* Due to DRX-K - probably need changes */ + int (*gate_ctrl)(struct dvb_frontend *, int); + struct semaphore pll_mutex; + bool dont_attach_fe1; }; @@ -115,7 +124,7 @@ static inline void print_err_status(struct em28xx *dev, } } -static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) +static inline int em28xx_dvb_isoc_copy(struct em28xx *dev, struct urb *urb) { int i; @@ -148,7 +157,7 @@ static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) return 0; } -static int start_streaming(struct em28xx_dvb *dvb) +static int em28xx_start_streaming(struct em28xx_dvb *dvb) { int rc; struct em28xx *dev = dvb->adapter.priv; @@ -160,13 +169,18 @@ static int start_streaming(struct em28xx_dvb *dvb) return rc; max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); + if (max_dvb_packet_size < 0) + return max_dvb_packet_size; + dprintk(1, "Using %d buffers each with %d bytes\n", + EM28XX_DVB_NUM_BUFS, + max_dvb_packet_size); return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, - dvb_isoc_copy); + em28xx_dvb_isoc_copy); } -static int stop_streaming(struct em28xx_dvb *dvb) +static int em28xx_stop_streaming(struct em28xx_dvb *dvb) { struct em28xx *dev = dvb->adapter.priv; @@ -177,7 +191,7 @@ static int stop_streaming(struct em28xx_dvb *dvb) return 0; } -static int start_feed(struct dvb_demux_feed *feed) +static int em28xx_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct em28xx_dvb *dvb = demux->priv; @@ -191,7 +205,7 @@ static int start_feed(struct dvb_demux_feed *feed) rc = dvb->nfeeds; if (dvb->nfeeds == 1) { - ret = start_streaming(dvb); + ret = em28xx_start_streaming(dvb); if (ret < 0) rc = ret; } @@ -200,7 +214,7 @@ static int start_feed(struct dvb_demux_feed *feed) return rc; } -static int stop_feed(struct dvb_demux_feed *feed) +static int em28xx_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct em28xx_dvb *dvb = demux->priv; @@ -210,7 +224,7 @@ static int stop_feed(struct dvb_demux_feed *feed) dvb->nfeeds--; if (0 == dvb->nfeeds) - err = stop_streaming(dvb); + err = em28xx_stop_streaming(dvb); mutex_unlock(&dvb->lock); return err; @@ -295,7 +309,80 @@ static struct drxd_config em28xx_drxd = { .disable_i2c_gate_ctrl = 1, }; -static int mt352_terratec_xs_init(struct dvb_frontend *fe) +struct drxk_config terratec_h5_drxk = { + .adr = 0x29, + .single_master = 1, + .no_i2c_bridge = 1, + .microcode_name = "dvb-usb-terratec-h5-drxk.fw", +}; + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct em28xx_dvb *dvb = fe->sec_priv; + int status; + + if (!dvb) + return -EINVAL; + + if (enable) { + down(&dvb->pll_mutex); + status = dvb->gate_ctrl(fe, 1); + } else { + status = dvb->gate_ctrl(fe, 0); + up(&dvb->pll_mutex); + } + return status; +} + +static void terratec_h5_init(struct em28xx *dev) +{ + int i; + struct em28xx_reg_seq terratec_h5_init[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + {EM2874_R80_GPIO, 0xf2, 0xff, 50}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + { -1, -1, -1, -1}, + }; + struct em28xx_reg_seq terratec_h5_end[] = { + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + {EM2874_R80_GPIO, 0xa6, 0xff, 50}, + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + { -1, -1, -1, -1}, + }; + struct { + unsigned char r[4]; + int len; + } regs[] = { + {{ 0x06, 0x02, 0x00, 0x31 }, 4}, + {{ 0x01, 0x02 }, 2}, + {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0xff, 0xaf }, 4}, + {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0x73, 0xaf }, 4}, + {{ 0x04, 0x00 }, 2}, + {{ 0x00, 0x04 }, 2}, + {{ 0x00, 0x04, 0x00, 0x0a }, 4}, + {{ 0x04, 0x14 }, 2}, + {{ 0x04, 0x14, 0x00, 0x00 }, 4}, + }; + + em28xx_gpio_set(dev, terratec_h5_init); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + msleep(10); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); + msleep(10); + + dev->i2c_client.addr = 0x82 >> 1; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + em28xx_gpio_set(dev, terratec_h5_end); +}; + +static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) { /* Values extracted from a USB trace of the Terratec Windows driver */ static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x2c }; @@ -327,7 +414,7 @@ static struct mt352_config terratec_xs_mt352_cfg = { .demod_address = (0x1e >> 1), .no_tuner = 1, .if2 = 45600, - .demod_init = mt352_terratec_xs_init, + .demod_init = em28xx_mt352_terratec_xs_init, }; static struct tda10023_config em28xx_tda10023_config = { @@ -353,11 +440,25 @@ static struct cxd2820r_config em28xx_cxd2820r_config = { static struct tda18271_config em28xx_cxd2820r_tda18271_config = { .output_opt = TDA18271_OUTPUT_LT_OFF, + .gate = TDA18271_GATE_DIGITAL, +}; + +static const struct tda10071_config em28xx_tda10071_config = { + .i2c_address = 0x55, /* (0xaa >> 1) */ + .i2c_wr_max = 64, + .ts_mode = TDA10071_TS_SERIAL, + .spec_inv = 0, + .xtal = 40444000, /* 40.444 MHz */ + .pll_multiplier = 20, +}; + +static const struct a8293_config em28xx_a8293_config = { + .i2c_addr = 0x08, /* (0x10 >> 1) */ }; /* ------------------------------------------------------------------ */ -static int attach_xc3028(u8 addr, struct em28xx *dev) +static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) { struct dvb_frontend *fe; struct xc2028_config cfg; @@ -387,10 +488,8 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) /* ------------------------------------------------------------------ */ -static int register_dvb(struct em28xx_dvb *dvb, - struct module *module, - struct em28xx *dev, - struct device *device) +static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, + struct em28xx *dev, struct device *device) { int result; @@ -437,8 +536,8 @@ static int register_dvb(struct em28xx_dvb *dvb, dvb->demux.priv = dvb; dvb->demux.filternum = 256; dvb->demux.feednum = 256; - dvb->demux.start_feed = start_feed; - dvb->demux.stop_feed = stop_feed; + dvb->demux.start_feed = em28xx_start_feed; + dvb->demux.stop_feed = em28xx_stop_feed; result = dvb_dmx_init(&dvb->demux); if (result < 0) { @@ -506,7 +605,7 @@ fail_adapter: return result; } -static void unregister_dvb(struct em28xx_dvb *dvb) +static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) { dvb_net_release(&dvb->net); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); @@ -516,15 +615,15 @@ static void unregister_dvb(struct em28xx_dvb *dvb) if (dvb->fe[1]) dvb_unregister_frontend(dvb->fe[1]); dvb_unregister_frontend(dvb->fe[0]); - if (dvb->fe[1]) + if (dvb->fe[1] && !dvb->dont_attach_fe1) dvb_frontend_detach(dvb->fe[1]); dvb_frontend_detach(dvb->fe[0]); dvb_unregister_adapter(&dvb->adapter); } -static int dvb_init(struct em28xx *dev) +static int em28xx_dvb_init(struct em28xx *dev) { - int result = 0; + int result = 0, mfe_shared = 0; struct em28xx_dvb *dvb; if (!dev->board.has_dvb) { @@ -546,7 +645,7 @@ static int dvb_init(struct em28xx *dev) em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); /* init frontend */ switch (dev->model) { - case EM2874_LEADERSHIP_ISDBT: + case EM2874_BOARD_LEADERSHIP_ISDBT: dvb->fe[0] = dvb_attach(s921_attach, &sharp_isdbt, &dev->i2c_adap); @@ -563,7 +662,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -572,7 +671,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_with_xc3028, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -583,7 +682,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_xc3028_no_i2c_gate, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -604,7 +703,7 @@ static int dvb_init(struct em28xx *dev) &dev->i2c_adap); } - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -614,7 +713,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(s5h1409_attach, &em28xx_s5h1409_with_xc3028, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -635,7 +734,7 @@ static int dvb_init(struct em28xx *dev) case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, &dev->i2c_adap, &dev->udev->dev); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -668,11 +767,9 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(cxd2820r_attach, &em28xx_cxd2820r_config, &dev->i2c_adap, NULL); if (dvb->fe[0]) { - struct i2c_adapter *i2c_tuner; - i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]); /* FE 0 attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; @@ -683,12 +780,59 @@ static int dvb_init(struct em28xx *dev) dvb->fe[1]->id = 1; /* FE 1 attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60, - i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[1]); /* leave FE 0 still active */ } + + mfe_shared = 1; } break; + case EM2884_BOARD_TERRATEC_H5: + terratec_h5_init(dev); + + dvb->dont_attach_fe1 = 1; + + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + + /* FIXME: do we need a pll semaphore? */ + dvb->fe[0]->sec_priv = dvb; + sema_init(&dvb->pll_mutex, 1); + dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl; + dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; + dvb->fe[1]->id = 1; + + /* Attach tda18271 to DVB-C frontend */ + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); + if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) { + result = -EINVAL; + goto out_free; + } + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); + + /* Hack - needed by drxk/tda18271c2dd */ + dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv; + memcpy(&dvb->fe[1]->ops.tuner_ops, + &dvb->fe[0]->ops.tuner_ops, + sizeof(dvb->fe[0]->ops.tuner_ops)); + + break; + case EM28174_BOARD_PCTV_460E: + /* attach demod */ + dvb->fe[0] = dvb_attach(tda10071_attach, + &em28xx_tda10071_config, &dev->i2c_adap); + + /* attach SEC */ + if (dvb->fe[0]) + dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, + &em28xx_a8293_config); + break; default: em28xx_errdev("/2: The frontend of your DVB/ATSC card" " isn't supported yet\n"); @@ -703,11 +847,14 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0]->callback = em28xx_tuner_callback; /* register everything */ - result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); + result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); if (result < 0) goto out_free; + /* MFE lock */ + dvb->adapter.mfe_shared = mfe_shared; + em28xx_info("Successfully loaded em28xx-dvb\n"); ret: em28xx_set_mode(dev, EM28XX_SUSPEND); @@ -720,7 +867,14 @@ out_free: goto ret; } -static int dvb_fini(struct em28xx *dev) +static inline void prevent_sleep(struct dvb_frontend_ops *ops) +{ + ops->set_voltage = NULL; + ops->sleep = NULL; + ops->tuner_ops.sleep = NULL; +} + +static int em28xx_dvb_fini(struct em28xx *dev) { if (!dev->board.has_dvb) { /* This device does not support the extension */ @@ -728,8 +882,19 @@ static int dvb_fini(struct em28xx *dev) } if (dev->dvb) { - unregister_dvb(dev->dvb); - kfree(dev->dvb); + struct em28xx_dvb *dvb = dev->dvb; + + if (dev->state & DEV_DISCONNECTED) { + /* We cannot tell the device to sleep + * once it has been unplugged. */ + if (dvb->fe[0]) + prevent_sleep(&dvb->fe[0]->ops); + if (dvb->fe[1]) + prevent_sleep(&dvb->fe[1]->ops); + } + + em28xx_unregister_dvb(dvb); + kfree(dvb); dev->dvb = NULL; } @@ -739,8 +904,8 @@ static int dvb_fini(struct em28xx *dev) static struct em28xx_ops dvb_ops = { .id = EM28XX_DVB, .name = "Em28xx dvb Extension", - .init = dvb_init, - .fini = dvb_fini, + .init = em28xx_dvb_init, + .fini = em28xx_dvb_fini, }; static int __init em28xx_dvb_register(void) diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 4739fc7..36f5a9b 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -181,16 +181,25 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, /* * em28xx_i2c_send_bytes() - * untested for more than 4 bytes */ static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf, short len, int stop) { int wrcount = 0; struct em28xx *dev = (struct em28xx *)data; + int write_timeout, ret; wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); + /* Seems to be required after a write */ + for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; + write_timeout -= 5) { + ret = dev->em28xx_read_reg(dev, 0x05); + if (!ret) + break; + msleep(5); + } + return wrcount; } @@ -218,9 +227,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, */ static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr) { - char msg; int ret; - msg = addr; ret = dev->em28xx_read_reg_req(dev, 2, addr); if (ret < 0) { @@ -332,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) struct em28xx_eeprom *em_eeprom = (void *)eedata; int i, err, size = len, block; - if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { + if (dev->chip_id == CHIP_ID_EM2874 || + dev->chip_id == CHIP_ID_EM28174 || + dev->chip_id == CHIP_ID_EM2884) { /* Empia switched to a 16-bit addressable eeprom in newer devices. While we could certainly write a routine to read the eeprom, there is nothing of use in there that cannot be diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index ba1ba86..679da48 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -372,6 +372,7 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) ir->get_key = default_polling_getkey; break; case CHIP_ID_EM2874: + case CHIP_ID_EM28174: ir->get_key = em2874_polling_getkey; em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); break; @@ -462,11 +463,11 @@ int em28xx_ir_fini(struct em28xx *dev) if (!ir) return 0; - em28xx_ir_stop(ir->rc); - rc_unregister_device(ir->rc); - kfree(ir); + if (ir->rc) + rc_unregister_device(ir->rc); /* done */ + kfree(ir); dev->ir = NULL; return 0; } diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index e92a28e..66f7923 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -201,6 +201,7 @@ enum em28xx_chip_id { CHIP_ID_EM2870 = 35, CHIP_ID_EM2883 = 36, CHIP_ID_EM2874 = 65, + CHIP_ID_EM2884 = 68, CHIP_ID_EM28174 = 113, }; diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 7b6461d..9b4557a 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -32,7 +32,6 @@ #include <linux/bitmap.h> #include <linux/usb.h> #include <linux/i2c.h> -#include <linux/version.h> #include <linux/mm.h> #include <linux/mutex.h> #include <linux/slab.h> @@ -50,7 +49,8 @@ "Sascha Sommer <saschasommer@freenet.de>" #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 2) + +#define EM28XX_VERSION "0.1.3" #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ @@ -72,6 +72,7 @@ do {\ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION(EM28XX_VERSION); static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; @@ -1155,6 +1156,21 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) return 0; } +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) { struct em28xx_fh *fh = priv; @@ -1757,8 +1773,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | @@ -1788,6 +1802,45 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct em28xx_fmt *fmt; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + + fmt = format_by_fourcc(fsize->pixel_format); + if (!fmt) { + em28xx_videodbg("Fourcc format (%08x) invalid.\n", + fsize->pixel_format); + return -EINVAL; + } + + if (dev->board.is_em2800) { + if (fsize->index > 1) + return -EINVAL; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = maxw / (1 + fsize->index); + fsize->discrete.height = maxh / (1 + fsize->index); + return 0; + } + + if (fsize->index != 0) + return -EINVAL; + + /* Report a continuous range */ + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = 48; + fsize->stepwise.min_height = 32; + fsize->stepwise.max_width = maxw; + fsize->stepwise.max_height = maxh; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + return 0; +} + /* Sliced VBI ioctls */ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) @@ -1976,7 +2029,6 @@ static int radio_querycap(struct file *file, void *priv, strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = EM28XX_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } @@ -2202,6 +2254,7 @@ static int em28xx_v4l2_close(struct file *filp) free the remaining resources */ if (dev->state & DEV_DISCONNECTED) { em28xx_release_resources(dev); + kfree(dev->alt_max_pkt_size); kfree(dev); return 0; } @@ -2342,10 +2395,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, @@ -2355,6 +2408,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_g_std = vidioc_g_std, + .vidioc_querystd = vidioc_querystd, .vidioc_s_std = vidioc_s_std, .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, @@ -2450,10 +2504,8 @@ int em28xx_register_analog_devices(struct em28xx *dev) u8 val; int ret; - printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n", - dev->name, - (EM28XX_VERSION_CODE >> 16) & 0xff, - (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); + printk(KERN_INFO "%s: v4l2 driver version %s\n", + dev->name, EM28XX_VERSION); /* set default norm */ dev->norm = em28xx_video_template.current_norm; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 3cca331..2a2cb7e 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -117,9 +117,10 @@ #define EM2800_BOARD_VC211A 74 #define EM2882_BOARD_DIKOM_DK300 75 #define EM2870_BOARD_KWORLD_A340 76 -#define EM2874_LEADERSHIP_ISDBT 77 +#define EM2874_BOARD_LEADERSHIP_ISDBT 77 #define EM28174_BOARD_PCTV_290E 78 - +#define EM2884_BOARD_TERRATEC_H5 79 +#define EM28174_BOARD_PCTV_460E 80 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -487,6 +488,8 @@ struct em28xx { int devno; /* marks the number of this device */ enum em28xx_chip_id chip_id; + int audio_ifnum; + struct v4l2_device v4l2_dev; struct em28xx_board board; @@ -503,6 +506,7 @@ struct em28xx { unsigned int has_audio_class:1; unsigned int has_alsa_audio:1; + unsigned int is_audio_only:1; /* Controls audio streaming */ struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ @@ -674,8 +678,6 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); void em28xx_wake_i2c(struct em28xx *dev); -void em28xx_remove_from_devlist(struct em28xx *dev); -void em28xx_add_into_devlist(struct em28xx *dev); int em28xx_register_extension(struct em28xx_ops *dev); void em28xx_unregister_extension(struct em28xx_ops *dev); void em28xx_init_extension(struct em28xx *dev); @@ -697,6 +699,9 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_release_resources(struct em28xx *dev); /* Provided by em28xx-input.c */ + +#ifdef CONFIG_VIDEO_EM28XX_RC + int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, @@ -709,6 +714,20 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev); int em28xx_ir_init(struct em28xx *dev); int em28xx_ir_fini(struct em28xx *dev); +#else + +#define em28xx_get_key_terratec NULL +#define em28xx_get_key_em_haup NULL +#define em28xx_get_key_pinnacle_usb_grey NULL +#define em28xx_get_key_winfast_usbii_deluxe NULL + +static inline void em28xx_register_snapshot_button(struct em28xx *dev) {} +static inline void em28xx_deregister_snapshot_button(struct em28xx *dev) {} +static inline int em28xx_ir_init(struct em28xx *dev) { return 0; } +static inline int em28xx_ir_fini(struct em28xx *dev) { return 0; } + +#endif + /* Provided by em28xx-vbi.c */ extern struct videobuf_queue_ops em28xx_vbi_qops; diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h index bf66189..337ded4 100644 --- a/drivers/media/video/et61x251/et61x251.h +++ b/drivers/media/video/et61x251/et61x251.h @@ -21,7 +21,6 @@ #ifndef _ET61X251_H_ #define _ET61X251_H_ -#include <linux/version.h> #include <linux/usb.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> @@ -166,45 +165,49 @@ et61x251_attach_sensor(struct et61x251_device* cam, #undef DBG #undef KDBG #ifdef ET61X251_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ - __FILE__, __func__, __LINE__ , ## args); \ - } \ +#define DBG(level, fmt, ...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1) \ + dev_err(&cam->usbdev->dev, fmt "\n", \ + ##__VA_ARGS__); \ + else if ((level) == 2) \ + dev_info(&cam->usbdev->dev, fmt "\n", \ + ##__VA_ARGS__); \ + else if ((level) >= 3) \ + dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ + __FILE__, __func__, __LINE__, \ + ##__VA_ARGS__); \ + } \ } while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("et61x251: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \ - __func__, __LINE__ , ## args); \ - } \ +#define KDBG(level, fmt, ...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1 || (level) == 2) \ + pr_info(fmt "\n", ##__VA_ARGS__); \ + else if ((level) == 3) \ + pr_debug("[%s:%s:%d] " fmt "\n", \ + __FILE__, __func__, __LINE__, \ + ##__VA_ARGS__); \ + } \ } while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ +#define V4LDBG(level, name, cmd) \ +do { \ + if (debug >= (level)) \ + v4l_print_ioctl(name, cmd); \ } while (0) #else -# define DBG(level, fmt, args...) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) +#define DBG(level, fmt, ...) do {;} while(0) +#define KDBG(level, fmt, ...) do {;} while(0) +#define V4LDBG(level, name, cmd) do {;} while(0) #endif #undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \ - __LINE__ , ## args) +#define PDBG(fmt, ...) \ + dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ + __FILE__, __func__, __LINE__, ##__VA_ARGS__) #undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ +#define PDBGG(fmt, args...) do {;} while (0) /* placeholder */ #endif /* _ET61X251_H_ */ diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index a982750..d3777c8 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -18,6 +18,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ***************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -48,8 +51,7 @@ #define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia" #define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define ET61X251_MODULE_LICENSE "GPL" -#define ET61X251_MODULE_VERSION "1:1.09" -#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9) +#define ET61X251_MODULE_VERSION "1.1.10" /*****************************************************************************/ @@ -1579,7 +1581,7 @@ et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) { struct v4l2_capability cap = { .driver = "et61x251", - .version = ET61X251_MODULE_VERSION_CODE, + .version = LINUX_VERSION_CODE, .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING, }; @@ -2480,16 +2482,8 @@ static long et61x251_ioctl_v4l2(struct file *filp, case VIDIOC_S_PARM: return et61x251_vidioc_s_parm(cam, arg); - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - case VIDIOC_ENUM_FRAMEINTERVALS: - return -EINVAL; - default: - return -EINVAL; + return -ENOTTY; } } diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c index 04b7fbb..ced2e16 100644 --- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c +++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ***************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "et61x251_sensor.h" diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 34ae2c2..103af3f 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -179,6 +179,16 @@ config USB_GSPCA_PAC7311 To compile this driver as a module, choose M here: the module will be called gspca_pac7311. +config USB_GSPCA_SE401 + tristate "SE401 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + Endpoints (formerly known as AOX) se401 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_se401. + config USB_GSPCA_SN9C2028 tristate "SONIX Dual-Mode USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA @@ -346,6 +356,16 @@ config USB_GSPCA_T613 To compile this driver as a module, choose M here: the module will be called gspca_t613. +config USB_GSPCA_TOPRO + tristate "TOPRO USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + TP6800 and TP6810 Topro chips. + + To compile this driver as a module, choose M here: the + module will be called gspca_topro. + config USB_GSPCA_TV8532 tristate "TV8532 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 802fbe1..f345f49 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_USB_GSPCA_OV534_9) += gspca_ov534_9.o obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o obj-$(CONFIG_USB_GSPCA_PAC7302) += gspca_pac7302.o obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o +obj-$(CONFIG_USB_GSPCA_SE401) += gspca_se401.o obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o obj-$(CONFIG_USB_GSPCA_SN9C20X) += gspca_sn9c20x.o obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o @@ -34,6 +35,7 @@ obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o +obj-$(CONFIG_USB_GSPCA_TOPRO) += gspca_topro.o obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o @@ -58,6 +60,7 @@ gspca_ov534_9-objs := ov534_9.o gspca_pac207-objs := pac207.o gspca_pac7302-objs := pac7302.o gspca_pac7311-objs := pac7311.o +gspca_se401-objs := se401.o gspca_sn9c2028-objs := sn9c2028.o gspca_sn9c20x-objs := sn9c20x.o gspca_sonixb-objs := sonixb.o @@ -76,6 +79,7 @@ gspca_stk014-objs := stk014.o gspca_stv0680-objs := stv0680.o gspca_sunplus-objs := sunplus.o gspca_t613-objs := t613.o +gspca_topro-objs := topro.o gspca_tv8532-objs := tv8532.o gspca_vc032x-objs := vc032x.o gspca_vicam-objs := vicam.o diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c index a09c470..6ae2616 100644 --- a/drivers/media/video/gspca/benq.c +++ b/drivers/media/video/gspca/benq.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "benq" #include "gspca.h" @@ -62,7 +64,7 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -84,20 +86,6 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - int ret; - - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, - gspca_dev->nbalt - 1); - if (ret < 0) { - err("usb_set_interface failed"); - return ret; - } -/* reg_w(gspca_dev, 0x0003, 0x0002); */ - return 0; -} - /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { @@ -113,7 +101,7 @@ static int sd_start(struct gspca_dev *gspca_dev) for (n = 0; n < 4; n++) { urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); if (!urb) { - err("usb_alloc_urb failed"); + pr_err("usb_alloc_urb failed\n"); return -ENOMEM; } gspca_dev->urb[n] = urb; @@ -123,7 +111,7 @@ static int sd_start(struct gspca_dev *gspca_dev) &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - err("usb_alloc_coherent failed"); + pr_err("usb_alloc_coherent failed\n"); return -ENOMEM; } urb->dev = gspca_dev->dev; @@ -181,7 +169,7 @@ static void sd_isoc_irq(struct urb *urb) if (gspca_dev->frozen) return; #endif - err("urb status: %d", urb->status); + pr_err("urb status: %d\n", urb->status); return; } @@ -209,7 +197,7 @@ static void sd_isoc_irq(struct urb *urb) if (st == 0) st = urb->iso_frame_desc[i].status; if (st) { - err("ISOC data error: [%d] status=%d", + pr_err("ISOC data error: [%d] status=%d\n", i, st); gspca_dev->last_packet_type = DISCARD_PACKET; continue; @@ -256,10 +244,10 @@ static void sd_isoc_irq(struct urb *urb) /* resubmit the URBs */ st = usb_submit_urb(urb0, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb(0) ret %d", st); + pr_err("usb_submit_urb(0) ret %d\n", st); st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb() ret %d", st); + pr_err("usb_submit_urb() ret %d\n", st); } /* sub-driver description */ @@ -269,7 +257,6 @@ static const struct sd_desc sd_desc = { .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, - .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 8b39849..4c56dbe 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "conex" #include "gspca.h" @@ -129,7 +131,7 @@ static void reg_r(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -169,7 +171,7 @@ static void reg_w(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); + pr_err("reg_w: buffer overflow\n"); return; } PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index f2a9451..f9b86b2 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -26,6 +26,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "cpia1" #include <linux/input.h> @@ -550,8 +552,7 @@ retry: gspca_dev->usb_buf, databytes, 1000); if (ret < 0) - err("usb_control_msg %02x, error %d", command[1], - ret); + pr_err("usb_control_msg %02x, error %d\n", command[1], ret); if (ret == -EPIPE && retries > 0) { retries--; @@ -1279,7 +1280,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev) cmd[7] = 0; ret = cpia_usb_transferCmd(gspca_dev, cmd); if (ret) { - err("ReadVPRegs(30,4,9,8) - failed: %d", ret); + pr_err("ReadVPRegs(30,4,9,8) - failed: %d\n", ret); return; } exp_acc = gspca_dev->usb_buf[0]; diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 4b2c483..0357d6d 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "etoms" #include "gspca.h" @@ -236,7 +238,7 @@ static void reg_r(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -274,7 +276,7 @@ static void reg_w(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); + pr_err("reg_w: buffer overflow\n"); return; } PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c index 987b4b6..ea48200 100644 --- a/drivers/media/video/gspca/finepix.c +++ b/drivers/media/video/gspca/finepix.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "finepix" #include "gspca.h" @@ -182,7 +184,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* Init the device */ ret = command(gspca_dev, 0); if (ret < 0) { - err("init failed %d", ret); + pr_err("init failed %d\n", ret); return ret; } @@ -194,14 +196,14 @@ static int sd_start(struct gspca_dev *gspca_dev) FPIX_MAX_TRANSFER, &len, FPIX_TIMEOUT); if (ret < 0) { - err("usb_bulk_msg failed %d", ret); + pr_err("usb_bulk_msg failed %d\n", ret); return ret; } /* Request a frame, but don't read it */ ret = command(gspca_dev, 1); if (ret < 0) { - err("frame request failed %d", ret); + pr_err("frame request failed %d\n", ret); return ret; } diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile index 13c9403..f511ecc 100644 --- a/drivers/media/video/gspca/gl860/Makefile +++ b/drivers/media/video/gspca/gl860/Makefile @@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \ gl860-ov9655.o \ gl860-mi2020.o -EXTRA_CFLAGS += -Idrivers/media/video/gspca +ccflags-y += -Idrivers/media/video/gspca diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index e8e071a..2ced3b7 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "gspca.h" #include "gl860.h" @@ -572,9 +575,8 @@ int gl860_RTx(struct gspca_dev *gspca_dev, } if (r < 0) - err("ctrl transfer failed %4d " - "[p%02x r%d v%04x i%04x len%d]", - r, pref, req, val, index, len); + pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n", + r, pref, req, val, index, len); else if (len > 1 && r < len) PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len); diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h index 49ad4ac..0330a02 100644 --- a/drivers/media/video/gspca/gl860/gl860.h +++ b/drivers/media/video/gspca/gl860/gl860.h @@ -18,7 +18,6 @@ */ #ifndef GL860_DEV_H #define GL860_DEV_H -#include <linux/version.h> #include "gspca.h" diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 08ce994..981501f 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -21,10 +21,11 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define MODULE_NAME "gspca" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#define GSPCA_VERSION "2.14.0" #include <linux/init.h> -#include <linux/version.h> #include <linux/fs.h> #include <linux/vmalloc.h> #include <linux/sched.h> @@ -54,8 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); - -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 13, 0) +MODULE_VERSION(GSPCA_VERSION); #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; @@ -148,7 +148,7 @@ static void int_irq(struct urb *urb) if (ret == 0) { ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) - err("Resubmit URB failed with error %i", ret); + pr_err("Resubmit URB failed with error %i\n", ret); } } @@ -177,8 +177,8 @@ static int gspca_input_connect(struct gspca_dev *dev) err = input_register_device(input_dev); if (err) { - err("Input device registration failed with error %i", - err); + pr_err("Input device registration failed with error %i\n", + err); input_dev->dev.parent = NULL; input_free_device(input_dev); } else { @@ -323,8 +323,8 @@ static void fill_frame(struct gspca_dev *gspca_dev, /* check the packet status and length */ st = urb->iso_frame_desc[i].status; if (st) { - err("ISOC data error: [%d] len=%d, status=%d", - i, len, st); + pr_err("ISOC data error: [%d] len=%d, status=%d\n", + i, len, st); gspca_dev->last_packet_type = DISCARD_PACKET; continue; } @@ -346,7 +346,7 @@ resubmit: /* resubmit the URB */ st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb() ret %d", st); + pr_err("usb_submit_urb() ret %d\n", st); } /* @@ -400,7 +400,7 @@ resubmit: if (gspca_dev->cam.bulk_nurbs != 0) { st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb() ret %d", st); + pr_err("usb_submit_urb() ret %d\n", st); } } @@ -443,8 +443,11 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, } else { switch (gspca_dev->last_packet_type) { case DISCARD_PACKET: - if (packet_type == LAST_PACKET) + if (packet_type == LAST_PACKET) { gspca_dev->last_packet_type = packet_type; + gspca_dev->image = NULL; + gspca_dev->image_len = 0; + } return; case LAST_PACKET: return; @@ -461,7 +464,7 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, } else { /* !! image is NULL only when last pkt is LAST or DISCARD if (gspca_dev->image == NULL) { - err("gspca_frame_add() image == NULL"); + pr_err("gspca_frame_add() image == NULL\n"); return; } */ @@ -494,19 +497,6 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, } EXPORT_SYMBOL(gspca_frame_add); -static int gspca_is_compressed(__u32 format) -{ - switch (format) { - case V4L2_PIX_FMT_MJPEG: - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_SPCA561: - case V4L2_PIX_FMT_PAC207: - case V4L2_PIX_FMT_MR97310A: - return 1; - } - return 0; -} - static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, enum v4l2_memory memory, unsigned int count) { @@ -522,7 +512,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, count = GSPCA_MAX_FRAMES - 1; gspca_dev->frbuf = vmalloc_32(frsz * count); if (!gspca_dev->frbuf) { - err("frame alloc failed"); + pr_err("frame alloc failed\n"); return -ENOMEM; } gspca_dev->capt_file = file; @@ -594,7 +584,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) return 0; ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); if (ret < 0) - err("set alt 0 err %d", ret); + pr_err("set alt 0 err %d\n", ret); return ret; } @@ -637,53 +627,104 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, return NULL; } +/* compute the minimum bandwidth for the current transfer */ +static u32 which_bandwidth(struct gspca_dev *gspca_dev) +{ + u32 bandwidth; + int i; + + i = gspca_dev->curr_mode; + bandwidth = gspca_dev->cam.cam_mode[i].sizeimage; + + /* if the image is compressed, estimate the mean image size */ + if (bandwidth < gspca_dev->cam.cam_mode[i].width * + gspca_dev->cam.cam_mode[i].height) + bandwidth /= 3; + + /* estimate the frame rate */ + if (gspca_dev->sd_desc->get_streamparm) { + struct v4l2_streamparm parm; + + parm.parm.capture.timeperframe.denominator = 15; + gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm); + bandwidth *= parm.parm.capture.timeperframe.denominator; + } else { + bandwidth *= 15; /* 15 fps */ + } + + PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth); + return bandwidth; +} + +/* endpoint table */ +#define MAX_ALT 16 +struct ep_tb_s { + u32 alt; + u32 bandwidth; +}; + /* - * 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). - * This routine may be called many times when the bandwidth is too small - * (the bandwidth is checked on urb submit). + * build the table of the endpoints + * and compute the minimum bandwidth for the image transfer */ -static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) +static int build_ep_tb(struct gspca_dev *gspca_dev, + struct usb_interface *intf, + int xfer, + struct ep_tb_s *ep_tb) { - struct usb_interface *intf; struct usb_host_endpoint *ep; - int xfer, i, ret; + int i, j, nbalt, psize, found; + u32 bandwidth, last_bw; - intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); - ep = NULL; - xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK - : USB_ENDPOINT_XFER_ISOC; - i = gspca_dev->alt; /* previous alt setting */ - if (gspca_dev->cam.reverse_alts) { - while (++i < gspca_dev->nbalt) { - ep = alt_xfer(&intf->altsetting[i], xfer); - if (ep) - break; - } - } else { - while (--i >= 0) { - ep = alt_xfer(&intf->altsetting[i], xfer); - if (ep) - break; - } - } - if (ep == NULL) { - err("no transfer endpoint found"); - return NULL; - } - PDEBUG(D_STREAM, "use alt %d ep 0x%02x", - i, ep->desc.bEndpointAddress); - gspca_dev->alt = i; /* memorize the current alt setting */ - if (gspca_dev->nbalt > 1) { - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); - if (ret < 0) { - err("set alt %d err %d", i, ret); - ep = NULL; + nbalt = intf->num_altsetting; + if (nbalt > MAX_ALT) + nbalt = MAX_ALT; /* fixme: should warn */ + + /* build the endpoint table */ + i = 0; + last_bw = 0; + for (;;) { + ep_tb->bandwidth = 2000 * 2000 * 120; + found = 0; + for (j = 0; j < nbalt; j++) { + ep = alt_xfer(&intf->altsetting[j], xfer); + if (ep == NULL) + continue; + psize = le16_to_cpu(ep->desc.wMaxPacketSize); + if (!gspca_dev->cam.bulk) /* isoc */ + psize = (psize & 0x07ff) * + (1 + ((psize >> 11) & 3)); + bandwidth = psize * ep->desc.bInterval * 1000; + if (gspca_dev->dev->speed == USB_SPEED_HIGH + || gspca_dev->dev->speed == USB_SPEED_SUPER) + bandwidth *= 8; + if (bandwidth <= last_bw) + continue; + if (bandwidth < ep_tb->bandwidth) { + ep_tb->bandwidth = bandwidth; + ep_tb->alt = j; + found = 1; + } } + if (!found) + break; + PDEBUG(D_STREAM, "alt %d bandwidth %d", + ep_tb->alt, ep_tb->bandwidth); + last_bw = ep_tb->bandwidth; + i++; + ep_tb++; + } + + /* get the requested bandwidth and start at the highest atlsetting */ + bandwidth = which_bandwidth(gspca_dev); + ep_tb--; + while (i > 1) { + ep_tb--; + if (ep_tb->bandwidth < bandwidth) + break; + i--; } - return ep; + return i; } /* @@ -728,7 +769,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, for (n = 0; n < nurbs; n++) { urb = usb_alloc_urb(npkt, GFP_KERNEL); if (!urb) { - err("usb_alloc_urb failed"); + pr_err("usb_alloc_urb failed\n"); return -ENOMEM; } gspca_dev->urb[n] = urb; @@ -738,7 +779,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - err("usb_alloc_coherent failed"); + pr_err("usb_alloc_coherent failed\n"); return -ENOMEM; } urb->dev = gspca_dev->dev; @@ -749,7 +790,10 @@ static int create_urbs(struct gspca_dev *gspca_dev, ep->desc.bEndpointAddress); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = ep->desc.bInterval; + if (gspca_dev->dev->speed == USB_SPEED_LOW) + urb->interval = ep->desc.bInterval; + else + urb->interval = 1 << (ep->desc.bInterval - 1); urb->complete = isoc_irq; urb->number_of_packets = npkt; for (i = 0; i < npkt; i++) { @@ -771,9 +815,11 @@ static int create_urbs(struct gspca_dev *gspca_dev, */ static int gspca_init_transfer(struct gspca_dev *gspca_dev) { + struct usb_interface *intf; struct usb_host_endpoint *ep; struct urb *urb; - int n, ret; + struct ep_tb_s ep_tb[MAX_ALT]; + int n, ret, xfer, alt, alt_idx; if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; @@ -791,30 +837,65 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->usb_err = 0; - /* set the higher alternate setting and - * loop until urb submit succeeds */ - if (gspca_dev->cam.reverse_alts) - gspca_dev->alt = 0; - else - gspca_dev->alt = gspca_dev->nbalt; - + /* do the specific subdriver stuff before endpoint selection */ + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + gspca_dev->alt = gspca_dev->cam.bulk ? intf->num_altsetting : 0; if (gspca_dev->sd_desc->isoc_init) { ret = gspca_dev->sd_desc->isoc_init(gspca_dev); if (ret < 0) goto unlock; } + xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK + : USB_ENDPOINT_XFER_ISOC; - gspca_input_destroy_urb(gspca_dev); - ep = get_ep(gspca_dev); - if (ep == NULL) { - ret = -EIO; - goto out; + /* if the subdriver forced an altsetting, get the endpoint */ + if (gspca_dev->alt != 0) { + gspca_dev->alt--; /* (previous version compatibility) */ + ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer); + if (ep == NULL) { + pr_err("bad altsetting %d\n", gspca_dev->alt); + ret = -EIO; + goto out; + } + ep_tb[0].alt = gspca_dev->alt; + alt_idx = 1; + } else { + + /* else, compute the minimum bandwidth + * and build the endpoint table */ + alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb); + if (alt_idx <= 0) { + pr_err("no transfer endpoint found\n"); + ret = -EIO; + goto unlock; + } } + + /* set the highest alternate setting and + * loop until urb submit succeeds */ + gspca_input_destroy_urb(gspca_dev); + + gspca_dev->alt = ep_tb[--alt_idx].alt; + alt = -1; for (;;) { + if (alt != gspca_dev->alt) { + alt = gspca_dev->alt; + if (gspca_dev->nbalt > 1) { + ret = usb_set_interface(gspca_dev->dev, + gspca_dev->iface, + alt); + if (ret < 0) { + if (ret == -ENOSPC) + goto retry; /*fixme: ugly*/ + pr_err("set alt %d err %d\n", alt, ret); + goto out; + } + } + } if (!gspca_dev->cam.no_urb_create) { - PDEBUG(D_STREAM, "init transfer alt %d", - gspca_dev->alt); - ret = create_urbs(gspca_dev, ep); + PDEBUG(D_STREAM, "init transfer alt %d", alt); + ret = create_urbs(gspca_dev, + alt_xfer(&intf->altsetting[alt], xfer)); if (ret < 0) { destroy_urbs(gspca_dev); goto out; @@ -848,29 +929,35 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) break; } if (ret >= 0) - break; + break; /* transfer is started */ + + /* something when wrong + * stop the webcam and free the transfer resources */ gspca_stream_off(gspca_dev); if (ret != -ENOSPC) { - err("usb_submit_urb alt %d err %d", - gspca_dev->alt, ret); + pr_err("usb_submit_urb alt %d err %d\n", + gspca_dev->alt, ret); goto out; } /* the bandwidth is not wide enough * negotiate or try a lower alternate setting */ +retry: PDEBUG(D_ERR|D_STREAM, - "bandwidth not wide enough - trying again"); + "alt %d - bandwidth not wide enough - trying again", + alt); msleep(20); /* wait for kill complete */ if (gspca_dev->sd_desc->isoc_nego) { ret = gspca_dev->sd_desc->isoc_nego(gspca_dev); if (ret < 0) goto out; } else { - ep = get_ep(gspca_dev); - if (ep == NULL) { + if (alt_idx <= 0) { + pr_err("no transfer endpoint found\n"); ret = -EIO; goto out; } + gspca_dev->alt = ep_tb[--alt_idx].alt; } } out: @@ -1041,7 +1128,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; /* no more format */ fmtdesc->pixelformat = fmt_tb[index]; - if (gspca_is_compressed(fmt_tb[index])) + if (gspca_dev->cam.cam_mode[i].sizeimage < + gspca_dev->cam.cam_mode[i].width * + gspca_dev->cam.cam_mode[i].height) fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED; fmtdesc->description[0] = fmtdesc->pixelformat & 0xff; fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff; @@ -1278,10 +1367,10 @@ static int vidioc_querycap(struct file *file, void *priv, ret = -ENODEV; goto out; } - strncpy((char *) cap->driver, gspca_dev->sd_desc->name, + strlcpy((char *) cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); if (gspca_dev->dev->product != NULL) { - strncpy((char *) cap->card, gspca_dev->dev->product, + strlcpy((char *) cap->card, gspca_dev->dev->product, sizeof cap->card); } else { snprintf((char *) cap->card, sizeof cap->card, @@ -1291,7 +1380,6 @@ static int vidioc_querycap(struct file *file, void *priv, } usb_make_path(gspca_dev->dev, (char *) cap->bus_info, sizeof(cap->bus_info)); - cap->version = DRIVER_VERSION_NUMBER; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; @@ -1460,7 +1548,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return -EINVAL; input->type = V4L2_INPUT_TYPE_CAMERA; input->status = gspca_dev->cam.input_flags; - strncpy(input->name, gspca_dev->sd_desc->name, + strlcpy(input->name, gspca_dev->sd_desc->name, sizeof input->name); return 0; } @@ -1609,7 +1697,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type buf_type) { struct gspca_dev *gspca_dev = priv; - int ret; + int i, ret; if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1640,6 +1728,8 @@ static int vidioc_streamoff(struct file *file, void *priv, wake_up_interruptible(&gspca_dev->wq); /* empty the transfer queues */ + for (i = 0; i < gspca_dev->nframes; i++) + gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS; atomic_set(&gspca_dev->fr_q, 0); atomic_set(&gspca_dev->fr_i, 0); gspca_dev->fr_o = 0; @@ -2193,19 +2283,20 @@ int gspca_dev_probe2(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); int ret; - PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct); + pr_info("%s-" GSPCA_VERSION " probing %04x:%04x\n", + sd_desc->name, id->idVendor, id->idProduct); /* create the device */ if (dev_size < sizeof *gspca_dev) dev_size = sizeof *gspca_dev; gspca_dev = kzalloc(dev_size, GFP_KERNEL); if (!gspca_dev) { - err("couldn't kzalloc gspca struct"); + pr_err("couldn't kzalloc gspca struct\n"); return -ENOMEM; } gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); if (!gspca_dev->usb_buf) { - err("out of memory"); + pr_err("out of memory\n"); ret = -ENOMEM; goto out; } @@ -2262,7 +2353,7 @@ int gspca_dev_probe2(struct usb_interface *intf, VFL_TYPE_GRABBER, -1); if (ret < 0) { - err("video_register_device err %d", ret); + pr_err("video_register_device err %d\n", ret); goto out; } @@ -2294,8 +2385,8 @@ int gspca_dev_probe(struct usb_interface *intf, /* we don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) { - err("%04x:%04x too many config", - id->idVendor, id->idProduct); + pr_err("%04x:%04x too many config\n", + id->idVendor, id->idProduct); return -ENODEV; } @@ -2478,10 +2569,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure); /* -- module insert / remove -- */ static int __init gspca_init(void) { - info("v%d.%d.%d registered", - (DRIVER_VERSION_NUMBER >> 16) & 0xff, - (DRIVER_VERSION_NUMBER >> 8) & 0xff, - DRIVER_VERSION_NUMBER & 0xff); + pr_info("v" GSPCA_VERSION " registered\n"); return 0; } static void __exit gspca_exit(void) diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 49e2fcb..e444f16 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -14,11 +14,12 @@ #ifdef GSPCA_DEBUG /* GSPCA our debug messages */ extern int gspca_debug; -#define PDEBUG(level, fmt, args...) \ - do {\ - if (gspca_debug & (level)) \ - printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \ - } while (0) +#define PDEBUG(level, fmt, ...) \ +do { \ + if (gspca_debug & (level)) \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + #define D_ERR 0x01 #define D_PROBE 0x02 #define D_CONF 0x04 @@ -29,17 +30,8 @@ extern int gspca_debug; #define D_USBO 0x00 #define D_V4L2 0x0100 #else -#define PDEBUG(level, fmt, args...) +#define PDEBUG(level, fmt, ...) #endif -#undef err -#define err(fmt, args...) \ - printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args) -#undef info -#define info(fmt, args...) \ - printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args) -#undef warn -#define warn(fmt, args...) \ - printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args) #define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ /* image transfers */ diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 1bd9c4b..8e3dabe 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -24,6 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "jeilinj" #include <linux/slab.h> @@ -113,8 +115,8 @@ static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) usb_sndbulkpipe(gspca_dev->dev, 3), gspca_dev->usb_buf, 2, NULL, 500); if (retval < 0) { - err("command write [%02x] error %d", - gspca_dev->usb_buf[0], retval); + pr_err("command write [%02x] error %d\n", + gspca_dev->usb_buf[0], retval); gspca_dev->usb_err = retval; } } @@ -131,8 +133,8 @@ static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) gspca_dev->usb_buf, 1, NULL, 500); response = gspca_dev->usb_buf[0]; if (retval < 0) { - err("read command [%02x] error %d", - gspca_dev->usb_buf[0], retval); + pr_err("read command [%02x] error %d\n", + gspca_dev->usb_buf[0], retval); gspca_dev->usb_err = retval; } } @@ -403,13 +405,7 @@ static int sd_config(struct gspca_dev *gspca_dev, dev->type = id->driver_info; gspca_dev->cam.ctrls = dev->ctrls; dev->quality = QUALITY_DEF; - dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ; - dev->ctrls[RED].def = RED_BALANCE_DEF; - dev->ctrls[GREEN].def = GREEN_BALANCE_DEF; - dev->ctrls[BLUE].def = BLUE_BALANCE_DEF; - PDEBUG(D_PROBE, - "JEILINJ camera detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + cam->cam_mode = jlj_mode; cam->nmodes = ARRAY_SIZE(jlj_mode); cam->bulk = 1; @@ -422,7 +418,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { int i; u8 *buf; - u8 stop_commands[][2] = { + static u8 stop_commands[][2] = { {0x71, 0x00}, {0x70, 0x09}, {0x71, 0x80}, diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c index 26fc206..acaef66 100644 --- a/drivers/media/video/gspca/kinect.c +++ b/drivers/media/video/gspca/kinect.c @@ -24,6 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "kinect" #include "gspca.h" @@ -34,11 +36,6 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); MODULE_LICENSE("GPL"); -#ifdef GSPCA_DEBUG -int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | - D_USBI | D_USBO | D_V4L2; -#endif - struct pkt_hdr { uint8_t magic[2]; uint8_t pad; @@ -141,7 +138,7 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, struct cam_hdr *rhdr = (void *)ibuf; if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) { - err("send_cmd: Invalid command length (0x%x)", cmd_len); + pr_err("send_cmd: Invalid command length (0x%x)\n", cmd_len); return -1; } @@ -157,7 +154,7 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd, sd->cam_tag, cmd_len, res); if (res < 0) { - err("send_cmd: Output control transfer failed (%d)", res); + pr_err("send_cmd: Output control transfer failed (%d)\n", res); return res; } @@ -166,33 +163,35 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, } while (actual_len == 0); PDEBUG(D_USBO, "Control reply: %d", res); if (actual_len < sizeof(*rhdr)) { - err("send_cmd: Input control transfer failed (%d)", res); + pr_err("send_cmd: Input control transfer failed (%d)\n", res); return res; } actual_len -= sizeof(*rhdr); if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) { - err("send_cmd: Bad magic %02x %02x", rhdr->magic[0], - rhdr->magic[1]); + pr_err("send_cmd: Bad magic %02x %02x\n", + rhdr->magic[0], rhdr->magic[1]); return -1; } if (rhdr->cmd != chdr->cmd) { - err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd); + pr_err("send_cmd: Bad cmd %02x != %02x\n", + rhdr->cmd, chdr->cmd); return -1; } if (rhdr->tag != chdr->tag) { - err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag); + pr_err("send_cmd: Bad tag %04x != %04x\n", + rhdr->tag, chdr->tag); return -1; } if (cpu_to_le16(rhdr->len) != (actual_len/2)) { - err("send_cmd: Bad len %04x != %04x", - cpu_to_le16(rhdr->len), (int)(actual_len/2)); + pr_err("send_cmd: Bad len %04x != %04x\n", + cpu_to_le16(rhdr->len), (int)(actual_len/2)); return -1; } if (actual_len > reply_len) { - warn("send_cmd: Data buffer is %d bytes long, but got %d bytes", - reply_len, actual_len); + pr_warn("send_cmd: Data buffer is %d bytes long, but got %d bytes\n", + reply_len, actual_len); memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len); } else { memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len); @@ -218,8 +217,8 @@ static int write_register(struct gspca_dev *gspca_dev, uint16_t reg, if (res < 0) return res; if (res != 2) { - warn("send_cmd returned %d [%04x %04x], 0000 expected", - res, reply[0], reply[1]); + pr_warn("send_cmd returned %d [%04x %04x], 0000 expected\n", + res, reply[0], reply[1]); } return 0; } @@ -353,8 +352,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) return; if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') { - warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag, - hdr->magic[0], hdr->magic[1]); + pr_warn("[Stream %02x] Invalid magic %02x%02x\n", + sd->stream_flag, hdr->magic[0], hdr->magic[1]); return; } @@ -368,7 +367,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen); else - warn("Packet type not recognized..."); + pr_warn("Packet type not recognized...\n"); } /* sub-driver description */ @@ -391,6 +390,7 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x045e, 0x02ae)}, + {USB_DEVICE(0x045e, 0x02bf)}, {} }; diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c index 5964691..f3f7fe0 100644 --- a/drivers/media/video/gspca/konica.c +++ b/drivers/media/video/gspca/konica.c @@ -28,6 +28,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "konica" #include <linux/input.h> @@ -200,7 +202,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 0, 1000); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -221,7 +223,7 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) 2, 1000); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -284,7 +286,7 @@ static int sd_start(struct gspca_dev *gspca_dev) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); return -EIO; } @@ -315,7 +317,7 @@ static int sd_start(struct gspca_dev *gspca_dev) le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize); urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); if (!urb) { - err("usb_alloc_urb failed"); + pr_err("usb_alloc_urb failed\n"); return -ENOMEM; } gspca_dev->urb[n] = urb; @@ -324,7 +326,7 @@ static int sd_start(struct gspca_dev *gspca_dev) GFP_KERNEL, &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - err("usb_buffer_alloc failed"); + pr_err("usb_buffer_alloc failed\n"); return -ENOMEM; } @@ -386,7 +388,7 @@ static void sd_isoc_irq(struct urb *urb) PDEBUG(D_ERR, "urb status: %d", urb->status); st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("resubmit urb error %d", st); + pr_err("resubmit urb error %d\n", st); return; } @@ -477,7 +479,7 @@ resubmit: } st = usb_submit_urb(status_urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb(status_urb) ret %d", st); + pr_err("usb_submit_urb(status_urb) ret %d\n", st); } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile index bf7a19a..7f52961 100644 --- a/drivers/media/video/gspca/m5602/Makefile +++ b/drivers/media/video/gspca/m5602/Makefile @@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \ m5602_s5k83a.o \ m5602_s5k4aa.o -EXTRA_CFLAGS += -Idrivers/media/video/gspca +ccflags-y += -Idrivers/media/video/gspca diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index a7722b1..67533e5 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_ov9650.h" #include "m5602_ov7660.h" #include "m5602_mt9m111.h" @@ -192,10 +194,9 @@ static void m5602_dump_bridge(struct sd *sd) 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); + pr_info("ALi m5602 address 0x%x contains 0x%x\n", i, val); } - info("Warning: The ALi m5602 webcam probably won't work " - "until it's power cycled"); + pr_info("Warning: The ALi m5602 webcam probably won't work until it's power cycled\n"); } static int m5602_probe_sensor(struct sd *sd) @@ -231,7 +232,7 @@ static int m5602_probe_sensor(struct sd *sd) return 0; /* More sensor probe function goes here */ - info("Failed to find a sensor"); + pr_info("Failed to find a sensor\n"); sd->sensor = NULL; return -ENODEV; } diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c index 0d605a5..6268aa2 100644 --- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_mt9m111.h" static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); @@ -163,7 +165,7 @@ int mt9m111_probe(struct sd *sd) if (force_sensor) { if (force_sensor == MT9M111_SENSOR) { - info("Forcing a %s sensor", mt9m111.name); + pr_info("Forcing a %s sensor\n", mt9m111.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -191,7 +193,7 @@ int mt9m111_probe(struct sd *sd) return -ENODEV; if ((data[0] == 0x14) && (data[1] == 0x3a)) { - info("Detected a mt9m111 sensor"); + pr_info("Detected a mt9m111 sensor\n"); goto sensor_found; } @@ -612,34 +614,34 @@ static void mt9m111_dump_registers(struct sd *sd) { u8 address, value[2] = {0x00, 0x00}; - info("Dumping the mt9m111 register state"); + pr_info("Dumping the mt9m111 register state\n"); - info("Dumping the mt9m111 sensor core registers"); + pr_info("Dumping the mt9m111 sensor core registers\n"); value[1] = MT9M111_SENSOR_CORE; m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); + pr_info("register 0x%x contains 0x%x%x\n", + address, value[0], value[1]); } - info("Dumping the mt9m111 color pipeline registers"); + pr_info("Dumping the mt9m111 color pipeline registers\n"); value[1] = MT9M111_COLORPIPE; m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); + pr_info("register 0x%x contains 0x%x%x\n", + address, value[0], value[1]); } - info("Dumping the mt9m111 camera control registers"); + pr_info("Dumping the mt9m111 camera control registers\n"); value[1] = MT9M111_CAMERA_CONTROL; m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); + pr_info("register 0x%x contains 0x%x%x\n", + address, value[0], value[1]); } - info("mt9m111 register state dump complete"); + pr_info("mt9m111 register state dump complete\n"); } diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c index b12f604..9a14835 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov7660.c +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_ov7660.h" static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); @@ -149,7 +151,7 @@ int ov7660_probe(struct sd *sd) if (force_sensor) { if (force_sensor == OV7660_SENSOR) { - info("Forcing an %s sensor", ov7660.name); + pr_info("Forcing an %s sensor\n", ov7660.name); goto sensor_found; } /* If we want to force another sensor, @@ -180,10 +182,10 @@ int ov7660_probe(struct sd *sd) if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) return -ENODEV; - info("Sensor reported 0x%x%x", prod_id, ver_id); + pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id); if ((prod_id == 0x76) && (ver_id == 0x60)) { - info("Detected a ov7660 sensor"); + pr_info("Detected a ov7660 sensor\n"); goto sensor_found; } return -ENODEV; @@ -457,17 +459,16 @@ static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val) static void ov7660_dump_registers(struct sd *sd) { int address; - info("Dumping the ov7660 register state"); + pr_info("Dumping the ov7660 register state\n"); for (address = 0; address < 0xa9; address++) { u8 value; m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", address, value); } - info("ov7660 register state dump complete"); + pr_info("ov7660 register state dump complete\n"); - info("Probing for which registers that are read/write"); + pr_info("Probing for which registers that are read/write\n"); for (address = 0; address < 0xff; address++) { u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; @@ -477,9 +478,9 @@ static void ov7660_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c index 703d486..2114a8b 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_ov9650.h" static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); @@ -299,7 +301,7 @@ int ov9650_probe(struct sd *sd) if (force_sensor) { if (force_sensor == OV9650_SENSOR) { - info("Forcing an %s sensor", ov9650.name); + pr_info("Forcing an %s sensor\n", ov9650.name); goto sensor_found; } /* If we want to force another sensor, @@ -330,7 +332,7 @@ int ov9650_probe(struct sd *sd) return -ENODEV; if ((prod_id == 0x96) && (ver_id == 0x52)) { - info("Detected an ov9650 sensor"); + pr_info("Detected an ov9650 sensor\n"); goto sensor_found; } return -ENODEV; @@ -850,17 +852,16 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) static void ov9650_dump_registers(struct sd *sd) { int address; - info("Dumping the ov9650 register state"); + pr_info("Dumping the ov9650 register state\n"); for (address = 0; address < 0xa9; address++) { u8 value; m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", address, value); } - info("ov9650 register state dump complete"); + pr_info("ov9650 register state dump complete\n"); - info("Probing for which registers that are read/write"); + pr_info("Probing for which registers that are read/write\n"); for (address = 0; address < 0xff; address++) { u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; @@ -870,9 +871,9 @@ static void ov9650_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c index 1febd34..b877169 100644 --- a/drivers/media/video/gspca/m5602/m5602_po1030.c +++ b/drivers/media/video/gspca/m5602/m5602_po1030.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_po1030.h" static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); @@ -197,7 +199,7 @@ int po1030_probe(struct sd *sd) if (force_sensor) { if (force_sensor == PO1030_SENSOR) { - info("Forcing a %s sensor", po1030.name); + pr_info("Forcing a %s sensor\n", po1030.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -221,7 +223,7 @@ int po1030_probe(struct sd *sd) return -ENODEV; if (dev_id_h == 0x30) { - info("Detected a po1030 sensor"); + pr_info("Detected a po1030 sensor\n"); goto sensor_found; } return -ENODEV; @@ -267,7 +269,7 @@ int po1030_init(struct sd *sd) break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -733,16 +735,15 @@ static void po1030_dump_registers(struct sd *sd) int address; u8 value = 0; - info("Dumping the po1030 sensor core registers"); + pr_info("Dumping the po1030 sensor core registers\n"); for (address = 0; address < 0x7f; address++) { m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", address, value); } - info("po1030 register state dump complete"); + pr_info("po1030 register state dump complete\n"); - info("Probing for which registers that are read/write"); + pr_info("Probing for which registers that are read/write\n"); for (address = 0; address < 0xff; address++) { u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; @@ -752,9 +753,9 @@ static void po1030_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index d27280b..cc8ec3f 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_s5k4aa.h" static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); @@ -240,7 +242,7 @@ int s5k4aa_probe(struct sd *sd) if (force_sensor) { if (force_sensor == S5K4AA_SENSOR) { - info("Forcing a %s sensor", s5k4aa.name); + pr_info("Forcing a %s sensor\n", s5k4aa.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -276,7 +278,7 @@ int s5k4aa_probe(struct sd *sd) data, 2); break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -292,7 +294,7 @@ int s5k4aa_probe(struct sd *sd) if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) return -ENODEV; else - info("Detected a s5k4aa sensor"); + pr_info("Detected a s5k4aa sensor\n"); sensor_found: sensor_settings = kmalloc( @@ -347,7 +349,7 @@ int s5k4aa_start(struct sd *sd) break; default: - err("Invalid stream command, exiting init"); + pr_err("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -383,7 +385,7 @@ int s5k4aa_start(struct sd *sd) break; default: - err("Invalid stream command, exiting init"); + pr_err("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -447,7 +449,7 @@ int s5k4aa_init(struct sd *sd) init_s5k4aa[i][1], data, 2); break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -686,20 +688,21 @@ static void s5k4aa_dump_registers(struct sd *sd) m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); - info("Dumping the s5k4aa register state for page 0x%x", page); + pr_info("Dumping the s5k4aa register state for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 value = 0; m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", + address, value); } } - info("s5k4aa register state dump complete"); + pr_info("s5k4aa register state dump complete\n"); for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); - info("Probing for which registers that are " - "read/write for page 0x%x", page); + pr_info("Probing for which registers that are read/write for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 old_value, ctrl_value, test_value = 0xff; @@ -708,14 +711,16 @@ static void s5k4aa_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", + address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", + address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); } } - info("Read/write register probing complete"); + pr_info("Read/write register probing complete\n"); m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); } diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c index fbd9154..1de743a 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kthread.h> #include "m5602_s5k83a.h" @@ -135,7 +137,7 @@ int s5k83a_probe(struct sd *sd) if (force_sensor) { if (force_sensor == S5K83A_SENSOR) { - info("Forcing a %s sensor", s5k83a.name); + pr_info("Forcing a %s sensor\n", s5k83a.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -168,7 +170,7 @@ int s5k83a_probe(struct sd *sd) if ((prod_id == 0xff) || (ver_id == 0xff)) return -ENODEV; else - info("Detected a s5k83a sensor"); + pr_info("Detected a s5k83a sensor\n"); sensor_found: sens_priv = kmalloc( @@ -227,7 +229,7 @@ int s5k83a_init(struct sd *sd) init_s5k83a[i][1], data, 2); break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -273,7 +275,7 @@ static int rotation_thread_function(void *data) s5k83a_get_rotation(sd, ®); if (previous_rotation != reg) { previous_rotation = reg; - info("Camera was flipped"); + pr_info("Camera was flipped\n"); s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); @@ -566,20 +568,20 @@ static void s5k83a_dump_registers(struct sd *sd) for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); - info("Dumping the s5k83a register state for page 0x%x", page); + pr_info("Dumping the s5k83a register state for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 val = 0; m5602_read_sensor(sd, address, &val, 1); - info("register 0x%x contains 0x%x", - address, val); + pr_info("register 0x%x contains 0x%x\n", address, val); } } - info("s5k83a register state dump complete"); + pr_info("s5k83a register state dump complete\n"); for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); - info("Probing for which registers that are read/write " - "for page 0x%x", page); + pr_info("Probing for which registers that are read/write for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 old_val, ctrl_val, test_val = 0xff; @@ -588,14 +590,16 @@ static void s5k83a_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_val, 1); if (ctrl_val == test_val) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", + address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", + address); /* Restore original val */ m5602_write_sensor(sd, address, &old_val, 1); } } - info("Read/write register probing complete"); + pr_info("Read/write register probing complete\n"); m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); } diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 0196209..ef45fa5 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "mars" #include "gspca.h" @@ -178,8 +180,8 @@ static void reg_w(struct gspca_dev *gspca_dev, &alen, 500); /* timeout in milliseconds */ if (ret < 0) { - err("reg write [%02x] error %d", - gspca_dev->usb_buf[0], ret); + pr_err("reg write [%02x] error %d\n", + gspca_dev->usb_buf[0], ret); gspca_dev->usb_err = ret; } } diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index 97e5079..473e813 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c @@ -40,6 +40,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "mr97310a" #include "gspca.h" @@ -267,7 +269,7 @@ static int mr_write(struct gspca_dev *gspca_dev, int len) usb_sndbulkpipe(gspca_dev->dev, 4), gspca_dev->usb_buf, len, NULL, 500); if (rc < 0) - err("reg write [%02x] error %d", + pr_err("reg write [%02x] error %d\n", gspca_dev->usb_buf[0], rc); return rc; } @@ -281,7 +283,7 @@ static int mr_read(struct gspca_dev *gspca_dev, int len) usb_rcvbulkpipe(gspca_dev->dev, 3), gspca_dev->usb_buf, len, NULL, 500); if (rc < 0) - err("reg read [%02x] error %d", + pr_err("reg read [%02x] error %d\n", gspca_dev->usb_buf[0], rc); return rc; } @@ -540,7 +542,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor_type = 1; break; default: - err("Unknown CIF Sensor id : %02x", + pr_err("Unknown CIF Sensor id : %02x\n", gspca_dev->usb_buf[1]); return -ENODEV; } @@ -575,10 +577,10 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor_type = 2; } else if ((gspca_dev->usb_buf[0] != 0x03) && (gspca_dev->usb_buf[0] != 0x04)) { - err("Unknown VGA Sensor id Byte 0: %02x", - gspca_dev->usb_buf[0]); - err("Defaults assumed, may not work"); - err("Please report this"); + pr_err("Unknown VGA Sensor id Byte 0: %02x\n", + gspca_dev->usb_buf[0]); + pr_err("Defaults assumed, may not work\n"); + pr_err("Please report this\n"); } /* Sakar Digital color needs to be adjusted. */ if ((gspca_dev->usb_buf[0] == 0x03) && @@ -595,10 +597,10 @@ static int sd_config(struct gspca_dev *gspca_dev, /* Nothing to do here. */ break; default: - err("Unknown VGA Sensor id Byte 1: %02x", - gspca_dev->usb_buf[1]); - err("Defaults assumed, may not work"); - err("Please report this"); + pr_err("Unknown VGA Sensor id Byte 1: %02x\n", + gspca_dev->usb_buf[1]); + pr_err("Defaults assumed, may not work\n"); + pr_err("Please report this\n"); } } PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d", diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index 8e754fd..7681814 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "nw80x" #include "gspca.h" @@ -1571,7 +1573,7 @@ static void reg_w(struct gspca_dev *gspca_dev, len, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1592,7 +1594,7 @@ static void reg_r(struct gspca_dev *gspca_dev, 0x00, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; return; } @@ -1802,7 +1804,8 @@ static int sd_config(struct gspca_dev *gspca_dev, } } if (webcam_chip[sd->webcam] != sd->bridge) { - err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge); + pr_err("Bad webcam type %d for NW80%d\n", + sd->webcam, sd->bridge); gspca_dev->usb_err = -ENODEV; return gspca_dev->usb_err; } diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 057e287..6a01b35 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -36,6 +36,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "ov519" #include <linux/input.h> @@ -134,6 +137,7 @@ enum sensors { SEN_OV7670, SEN_OV76BE, SEN_OV8610, + SEN_OV9600, }; /* Note this is a bit of a hack, but the w9968cf driver needs the code for all @@ -340,6 +344,10 @@ static const unsigned ctrl_dis[] = { (1 << EXPOSURE) | (1 << AUTOGAIN) | (1 << FREQ), +[SEN_OV9600] = ((1 << NCTRL) - 1) /* no control */ + ^ ((1 << EXPOSURE) /* but exposure */ + | (1 << AUTOGAIN)), /* and autogain */ + }; static const struct v4l2_pix_format ov519_vga_mode[] = { @@ -525,6 +533,17 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; +static const struct v4l2_pix_format ovfx2_ov9600_mode[] = { + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; /* Registers common to OV511 / OV518 */ #define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ @@ -1807,6 +1826,22 @@ static const struct ov_i2c_regvals norm_7660[] = { | OV7670_COM8_AEC}, {0xa1, 0xc8} }; +static const struct ov_i2c_regvals norm_9600[] = { + {0x12, 0x80}, + {0x0c, 0x28}, + {0x11, 0x80}, + {0x13, 0xb5}, + {0x14, 0x3e}, + {0x1b, 0x04}, + {0x24, 0xb0}, + {0x25, 0x90}, + {0x26, 0x94}, + {0x35, 0x90}, + {0x37, 0x07}, + {0x38, 0x08}, + {0x01, 0x8e}, + {0x02, 0x85} +}; /* 7670. Defaults taken from OmniVision provided data, * as provided by Jonathan Corbet of OLPC */ @@ -2139,7 +2174,7 @@ static void reg_w(struct sd *sd, u16 index, u16 value) sd->gspca_dev.usb_buf, 1, 500); leave: if (ret < 0) { - err("reg_w %02x failed %d", index, ret); + pr_err("reg_w %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; return; } @@ -2178,7 +2213,7 @@ static int reg_r(struct sd *sd, u16 index) PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, ret); } else { - err("reg_r %02x failed %d", index, ret); + pr_err("reg_r %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } @@ -2203,7 +2238,7 @@ static int reg_r8(struct sd *sd, if (ret >= 0) { ret = sd->gspca_dev.usb_buf[0]; } else { - err("reg_r8 %02x failed %d", index, ret); + pr_err("reg_r8 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } @@ -2256,7 +2291,7 @@ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n) 0, index, sd->gspca_dev.usb_buf, n, 500); if (ret < 0) { - err("reg_w32 %02x failed %d", index, ret); + pr_err("reg_w32 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } } @@ -2400,9 +2435,12 @@ static int ov518_i2c_r(struct sd *sd, u8 reg) /* Initiate 2-byte write cycle */ reg_w(sd, R518_I2C_CTL, 0x03); + reg_r8(sd, R518_I2C_CTL); /* Initiate 2-byte read cycle */ reg_w(sd, R518_I2C_CTL, 0x05); + reg_r8(sd, R518_I2C_CTL); + value = reg_r(sd, R51x_I2C_DATA); PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value); return value; @@ -2422,7 +2460,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value) (u16) value, (u16) reg, NULL, 0, 500); if (ret < 0) { - err("ovfx2_i2c_w %02x failed %d", reg, ret); + pr_err("ovfx2_i2c_w %02x failed %d\n", reg, ret); sd->gspca_dev.usb_err = ret; } @@ -2446,7 +2484,7 @@ static int ovfx2_i2c_r(struct sd *sd, u8 reg) ret = sd->gspca_dev.usb_buf[0]; PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret); } else { - err("ovfx2_i2c_r %02x failed %d", reg, ret); + pr_err("ovfx2_i2c_r %02x failed %d\n", reg, ret); sd->gspca_dev.usb_err = ret; } @@ -2686,13 +2724,13 @@ static void write_i2c_regvals(struct sd *sd, * ***************************************************************************/ -/* This initializes the OV2x10 / OV3610 / OV3620 */ +/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */ static void ov_hires_configure(struct sd *sd) { int high, low; if (sd->bridge != BRIDGE_OVFX2) { - err("error hires sensors only supported with ovfx2"); + pr_err("error hires sensors only supported with ovfx2\n"); return; } @@ -2702,19 +2740,32 @@ static void ov_hires_configure(struct sd *sd) high = i2c_r(sd, 0x0a); low = i2c_r(sd, 0x0b); /* info("%x, %x", high, low); */ - if (high == 0x96 && low == 0x40) { - PDEBUG(D_PROBE, "Sensor is an OV2610"); - sd->sensor = SEN_OV2610; - } else if (high == 0x96 && low == 0x41) { - PDEBUG(D_PROBE, "Sensor is an OV2610AE"); - sd->sensor = SEN_OV2610AE; - } else if (high == 0x36 && (low & 0x0f) == 0x00) { - PDEBUG(D_PROBE, "Sensor is an OV3610"); - sd->sensor = SEN_OV3610; - } else { - err("Error unknown sensor type: %02x%02x", - high, low); + switch (high) { + case 0x96: + switch (low) { + case 0x40: + PDEBUG(D_PROBE, "Sensor is a OV2610"); + sd->sensor = SEN_OV2610; + return; + case 0x41: + PDEBUG(D_PROBE, "Sensor is a OV2610AE"); + sd->sensor = SEN_OV2610AE; + return; + case 0xb1: + PDEBUG(D_PROBE, "Sensor is a OV9600"); + sd->sensor = SEN_OV9600; + return; + } + break; + case 0x36: + if ((low & 0x0f) == 0x00) { + PDEBUG(D_PROBE, "Sensor is a OV3610"); + sd->sensor = SEN_OV3610; + return; + } + break; } + pr_err("Error unknown sensor type: %02x%02x\n", high, low); } /* This initializes the OV8110, OV8610 sensor. The OV8110 uses @@ -2735,7 +2786,7 @@ static void ov8xx0_configure(struct sd *sd) if ((rc & 3) == 1) sd->sensor = SEN_OV8610; else - err("Unknown image sensor version: %d", rc & 3); + pr_err("Unknown image sensor version: %d\n", rc & 3); } /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses @@ -2792,8 +2843,8 @@ static void ov7xx0_configure(struct sd *sd) if (high == 0x76) { switch (low) { case 0x30: - err("Sensor is an OV7630/OV7635"); - err("7630 is not supported by this driver"); + pr_err("Sensor is an OV7630/OV7635\n"); + pr_err("7630 is not supported by this driver\n"); return; case 0x40: PDEBUG(D_PROBE, "Sensor is an OV7645"); @@ -2810,7 +2861,6 @@ static void ov7xx0_configure(struct sd *sd) case 0x60: PDEBUG(D_PROBE, "Sensor is a OV7660"); sd->sensor = SEN_OV7660; - sd->invert_led = 0; break; default: PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); @@ -2821,7 +2871,7 @@ static void ov7xx0_configure(struct sd *sd) sd->sensor = SEN_OV7620; } } else { - err("Unknown image sensor version: %d", rc & 3); + pr_err("Unknown image sensor version: %d\n", rc & 3); } } @@ -2844,8 +2894,7 @@ static void ov6xx0_configure(struct sd *sd) switch (rc) { case 0x00: sd->sensor = SEN_OV6630; - warn("WARNING: Sensor is an OV66308. Your camera may have"); - warn("been misdetected in previous driver versions."); + pr_warn("WARNING: Sensor is an OV66308. Your camera may have been misdetected in previous driver versions.\n"); break; case 0x01: sd->sensor = SEN_OV6620; @@ -2861,11 +2910,10 @@ static void ov6xx0_configure(struct sd *sd) break; case 0x90: sd->sensor = SEN_OV6630; - warn("WARNING: Sensor is an OV66307. Your camera may have"); - warn("been misdetected in previous driver versions."); + pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n"); break; default: - err("FATAL: Unknown sensor version: 0x%02x", rc); + pr_err("FATAL: Unknown sensor version: 0x%02x\n", rc); return; } @@ -3289,7 +3337,6 @@ static int sd_config(struct gspca_dev *gspca_dev, case BRIDGE_OV519: cam->cam_mode = ov519_vga_mode; cam->nmodes = ARRAY_SIZE(ov519_vga_mode); - sd->invert_led = !sd->invert_led; break; case BRIDGE_OVFX2: cam->cam_mode = ov519_vga_mode; @@ -3359,7 +3406,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) { ov_hires_configure(sd); } else { - err("Can't determine sensor slave IDs"); + pr_err("Can't determine sensor slave IDs\n"); goto error; } @@ -3400,6 +3447,10 @@ static int sd_init(struct gspca_dev *gspca_dev) cam->cam_mode = ovfx2_ov3610_mode; cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode); break; + case SEN_OV9600: + cam->cam_mode = ovfx2_ov9600_mode; + cam->nmodes = ARRAY_SIZE(ovfx2_ov9600_mode); + break; default: if (sd->sif) { cam->cam_mode = ov519_sif_mode; @@ -3497,6 +3548,12 @@ static int sd_init(struct gspca_dev *gspca_dev) case SEN_OV8610: write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)); break; + case SEN_OV9600: + write_i2c_regvals(sd, norm_9600, ARRAY_SIZE(norm_9600)); + + /* enable autoexpo */ +/* i2c_w_mask(sd, 0x13, 0x05, 0x05); */ + break; } return gspca_dev->usb_err; error: @@ -3534,7 +3591,7 @@ static void ov511_mode_init_regs(struct sd *sd) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); sd->gspca_dev.usb_err = -EIO; return; } @@ -3657,7 +3714,7 @@ static void ov518_mode_init_regs(struct sd *sd) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); sd->gspca_dev.usb_err = -EIO; return; } @@ -4085,6 +4142,33 @@ static void mode_init_ov_sensor_regs(struct sd *sd) i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ break; + case SEN_OV9600: { + const struct ov_i2c_regvals *vals; + static const struct ov_i2c_regvals sxga_15[] = { + {0x11, 0x80}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75} + }; + static const struct ov_i2c_regvals sxga_7_5[] = { + {0x11, 0x81}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75} + }; + static const struct ov_i2c_regvals vga_30[] = { + {0x11, 0x81}, {0x14, 0x7e}, {0x24, 0x70}, {0x25, 0x60} + }; + static const struct ov_i2c_regvals vga_15[] = { + {0x11, 0x83}, {0x14, 0x3e}, {0x24, 0x80}, {0x25, 0x70} + }; + + /* frame rates: + * 15fps / 7.5 fps for 1280x1024 + * 30fps / 15fps for 640x480 + */ + i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0x40); + if (qvga) + vals = sd->frame_rate < 30 ? vga_15 : vga_30; + else + vals = sd->frame_rate < 15 ? sxga_7_5 : sxga_15; + write_i2c_regvals(sd, vals, ARRAY_SIZE(sxga_15)); + return; + } default: return; } @@ -4120,6 +4204,7 @@ static void set_ov_sensor_window(struct sd *sd) case SEN_OV2610AE: case SEN_OV3610: case SEN_OV7670: + case SEN_OV9600: mode_init_ov_sensor_regs(sd); return; case SEN_OV7660: @@ -4919,23 +5004,24 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF }, - {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4052), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4064), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4068), + {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, - {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x054c, 0x0155), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 }, {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 }, - {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x0519), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x05a9, 0x0530), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, {USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 }, {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 }, diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 0c6369b..76907ec 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -28,6 +28,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "ov534" #include "gspca.h" @@ -775,7 +777,7 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); if (ret < 0) { - err("write failed %d", ret); + pr_err("write failed %d\n", ret); gspca_dev->usb_err = ret; } } @@ -794,7 +796,7 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]); if (ret < 0) { - err("read failed %d", ret); + pr_err("read failed %d\n", ret); gspca_dev->usb_err = ret; } return gspca_dev->usb_buf[0]; @@ -858,7 +860,7 @@ static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); if (!sccb_check_status(gspca_dev)) { - err("sccb_reg_write failed"); + pr_err("sccb_reg_write failed\n"); gspca_dev->usb_err = -EIO; } } @@ -868,11 +870,11 @@ static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); if (!sccb_check_status(gspca_dev)) - err("sccb_reg_read failed 1"); + pr_err("sccb_reg_read failed 1\n"); ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); if (!sccb_check_status(gspca_dev)) - err("sccb_reg_read failed 2"); + pr_err("sccb_reg_read failed 2\n"); return ov534_reg_read(gspca_dev, OV534_REG_READ); } diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index aaf5428..b3b1ea6 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -1,7 +1,7 @@ /* - * ov534-ov965x gspca driver + * ov534-ov9xxx gspca driver * - * Copyright (C) 2009-2010 Jean-Francois Moine http://moinejf.free.fr + * Copyright (C) 2009-2011 Jean-Francois Moine http://moinejf.free.fr * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> * Copyright (C) 2008 Jim Paris <jim@jtan.com> * @@ -24,6 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "ov534_9" #include "gspca.h" @@ -45,39 +47,44 @@ MODULE_AUTHOR("Jean-Francois Moine <moinejf@free.fr>"); MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver"); MODULE_LICENSE("GPL"); +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + AUTOGAIN, + EXPOSURE, + SHARPNESS, + SATUR, + LIGHTFREQ, + NCTRLS /* number of controls */ +}; + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + struct gspca_ctrl ctrls[NCTRLS]; __u32 last_pts; u8 last_fid; - u8 brightness; - u8 contrast; - u8 autogain; - u8 exposure; - s8 sharpness; - u8 satur; - u8 freq; + u8 sensor; +}; +enum sensors { + SENSOR_OV965x, /* ov9657 */ + SENSOR_OV971x, /* ov9712 */ + NSENSORS }; /* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { /* 0 */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setautogain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static void setsharpness(struct gspca_dev *gspca_dev); +static void setsatur(struct gspca_dev *gspca_dev); +static void setlightfreq(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -85,13 +92,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 15, .step = 1, -#define BRIGHTNESS_DEF 7 - .default_value = BRIGHTNESS_DEF, + .default_value = 7 }, - .set = sd_setbrightness, - .get = sd_getbrightness, + .set_control = setbrightness }, - { /* 1 */ +[CONTRAST] = { { .id = V4L2_CID_CONTRAST, .type = V4L2_CTRL_TYPE_INTEGER, @@ -99,13 +104,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 15, .step = 1, -#define CONTRAST_DEF 3 - .default_value = CONTRAST_DEF, + .default_value = 3 }, - .set = sd_setcontrast, - .get = sd_getcontrast, + .set_control = setcontrast }, - { /* 2 */ +[AUTOGAIN] = { { .id = V4L2_CID_AUTOGAIN, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -116,11 +119,9 @@ static const struct ctrl sd_ctrls[] = { #define AUTOGAIN_DEF 1 .default_value = AUTOGAIN_DEF, }, - .set = sd_setautogain, - .get = sd_getautogain, + .set_control = setautogain }, -#define EXPO_IDX 3 - { /* 3 */ +[EXPOSURE] = { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -128,13 +129,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 3, .step = 1, -#define EXPO_DEF 0 - .default_value = EXPO_DEF, + .default_value = 0 }, - .set = sd_setexposure, - .get = sd_getexposure, + .set_control = setexposure }, - { /* 4 */ +[SHARPNESS] = { { .id = V4L2_CID_SHARPNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -142,13 +141,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = -1, /* -1 = auto */ .maximum = 4, .step = 1, -#define SHARPNESS_DEF -1 - .default_value = SHARPNESS_DEF, + .default_value = -1 }, - .set = sd_setsharpness, - .get = sd_getsharpness, + .set_control = setsharpness }, - { /* 5 */ +[SATUR] = { { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, @@ -156,13 +153,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 4, .step = 1, -#define SATUR_DEF 2 - .default_value = SATUR_DEF, + .default_value = 2 }, - .set = sd_setsatur, - .get = sd_getsatur, + .set_control = setsatur }, - { +[LIGHTFREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, .type = V4L2_CTRL_TYPE_MENU, @@ -170,11 +165,9 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ .step = 1, -#define FREQ_DEF 0 - .default_value = FREQ_DEF, + .default_value = 0 }, - .set = sd_setfreq, - .get = sd_getfreq, + .set_control = setlightfreq }, }; @@ -206,6 +199,14 @@ static const struct v4l2_pix_format ov965x_mode[] = { .colorspace = V4L2_COLORSPACE_JPEG}, }; +static const struct v4l2_pix_format ov971x_mode[] = { + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB + } +}; + static const u8 bridge_init[][2] = { {0x88, 0xf8}, {0x89, 0xff}, @@ -240,7 +241,7 @@ static const u8 bridge_init[][2] = { {0x94, 0x11}, }; -static const u8 sensor_init[][2] = { +static const u8 ov965x_init[][2] = { {0x12, 0x80}, /* com7 - SSCB reset */ {0x00, 0x00}, /* gain */ {0x01, 0x80}, /* blue */ @@ -450,7 +451,7 @@ static const u8 bridge_init_2[][2] = { {0x94, 0x11}, }; -static const u8 sensor_init_2[][2] = { +static const u8 ov965x_init_2[][2] = { {0x3b, 0xc4}, {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -492,7 +493,65 @@ static const u8 sensor_init_2[][2] = { {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ }; -static const u8 sensor_start_1_vga[][2] = { /* same for qvga */ +static const u8 ov971x_init[][2] = { + {0x12, 0x80}, + {0x09, 0x10}, + {0x1e, 0x07}, + {0x5f, 0x18}, + {0x69, 0x04}, + {0x65, 0x2a}, + {0x68, 0x0a}, + {0x39, 0x28}, + {0x4d, 0x90}, + {0xc1, 0x80}, + {0x0c, 0x30}, + {0x6d, 0x02}, + {0x96, 0xf1}, + {0xbc, 0x68}, + {0x12, 0x00}, + {0x3b, 0x00}, + {0x97, 0x80}, + {0x17, 0x25}, + {0x18, 0xa2}, + {0x19, 0x01}, + {0x1a, 0xca}, + {0x03, 0x0a}, + {0x32, 0x07}, + {0x98, 0x40}, /*{0x98, 0x00},*/ + {0x99, 0xA0}, /*{0x99, 0x00},*/ + {0x9a, 0x01}, /*{0x9a, 0x00},*/ + {0x57, 0x00}, + {0x58, 0x78}, /*{0x58, 0xc8},*/ + {0x59, 0x50}, /*{0x59, 0xa0},*/ + {0x4c, 0x13}, + {0x4b, 0x36}, + {0x3d, 0x3c}, + {0x3e, 0x03}, + {0xbd, 0x50}, /*{0xbd, 0xa0},*/ + {0xbe, 0x78}, /*{0xbe, 0xc8},*/ + {0x4e, 0x55}, + {0x4f, 0x55}, + {0x50, 0x55}, + {0x51, 0x55}, + {0x24, 0x55}, + {0x25, 0x40}, + {0x26, 0xa1}, + {0x5c, 0x59}, + {0x5d, 0x00}, + {0x11, 0x00}, + {0x2a, 0x98}, + {0x2b, 0x06}, + {0x2d, 0x00}, + {0x2e, 0x00}, + {0x13, 0xa5}, + {0x14, 0x40}, + {0x4a, 0x00}, + {0x49, 0xce}, + {0x22, 0x03}, + {0x09, 0x00} +}; + +static const u8 ov965x_start_1_vga[][2] = { /* same for qvga */ {0x12, 0x62}, /* com7 - 30fps VGA YUV */ {0x36, 0xfa}, /* aref3 */ {0x69, 0x0a}, /* hv */ @@ -515,7 +574,7 @@ static const u8 sensor_start_1_vga[][2] = { /* same for qvga */ {0xc0, 0xaa}, }; -static const u8 sensor_start_1_svga[][2] = { +static const u8 ov965x_start_1_svga[][2] = { {0x12, 0x02}, /* com7 - YUYV - VGA 15 full resolution */ {0x36, 0xf8}, /* aref3 */ {0x69, 0x02}, /* hv */ @@ -537,7 +596,7 @@ static const u8 sensor_start_1_svga[][2] = { {0xc0, 0xe2}, }; -static const u8 sensor_start_1_xga[][2] = { +static const u8 ov965x_start_1_xga[][2] = { {0x12, 0x02}, /* com7 */ {0x36, 0xf8}, /* aref3 */ {0x69, 0x02}, /* hv */ @@ -560,7 +619,7 @@ static const u8 sensor_start_1_xga[][2] = { {0xc0, 0xe2}, }; -static const u8 sensor_start_1_sxga[][2] = { +static const u8 ov965x_start_1_sxga[][2] = { {0x12, 0x02}, /* com7 */ {0x36, 0xf8}, /* aref3 */ {0x69, 0x02}, /* hv */ @@ -709,7 +768,7 @@ static const u8 bridge_start_sxga[][2] = { {0x94, 0x11}, }; -static const u8 sensor_start_2_qvga[][2] = { +static const u8 ov965x_start_2_qvga[][2] = { {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */ {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -727,7 +786,7 @@ static const u8 sensor_start_2_qvga[][2] = { {0x3a, 0x80}, /* tslb - yuyv */ }; -static const u8 sensor_start_2_vga[][2] = { +static const u8 ov965x_start_2_vga[][2] = { {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -743,7 +802,7 @@ static const u8 sensor_start_2_vga[][2] = { {0x2d, 0x00}, /* advfl */ }; -static const u8 sensor_start_2_svga[][2] = { /* same for xga */ +static const u8 ov965x_start_2_svga[][2] = { /* same for xga */ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -757,7 +816,7 @@ static const u8 sensor_start_2_svga[][2] = { /* same for xga */ {0xa3, 0x41}, /* bd60 */ }; -static const u8 sensor_start_2_sxga[][2] = { +static const u8 ov965x_start_2_sxga[][2] = { {0x13, 0xe0}, /* com8 */ {0x00, 0x00}, {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ @@ -785,7 +844,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); if (ret < 0) { - err("reg_w failed %d", ret); + pr_err("reg_w failed %d\n", ret); gspca_dev->usb_err = ret; } } @@ -810,7 +869,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg) 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } return gspca_dev->usb_buf[0]; @@ -848,7 +907,7 @@ static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); if (!sccb_check_status(gspca_dev)) - err("sccb_write failed"); + pr_err("sccb_write failed\n"); } static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg) @@ -856,11 +915,11 @@ static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg) reg_w(gspca_dev, OV534_REG_SUBADDR, reg); reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); if (!sccb_check_status(gspca_dev)) - err("sccb_read failed 1"); + pr_err("sccb_read failed 1\n"); reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); if (!sccb_check_status(gspca_dev)) - err("sccb_read failed 2"); + pr_err("sccb_read failed 2\n"); return reg_r(gspca_dev, OV534_REG_READ); } @@ -922,7 +981,9 @@ static void setbrightness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; - val = sd->brightness; + if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) + return; + val = sd->ctrls[BRIGHTNESS].val; if (val < 8) val = 15 - val; /* f .. 8 */ else @@ -935,8 +996,10 @@ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (gspca_dev->ctrl_dis & (1 << CONTRAST)) + return; sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */ - sd->contrast << 4); + sd->ctrls[CONTRAST].val << 4); } static void setautogain(struct gspca_dev *gspca_dev) @@ -944,10 +1007,12 @@ static void setautogain(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) + return; /*fixme: should adjust agc/awb/aec by different controls */ val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->autogain) + if (sd->ctrls[AUTOGAIN].val) val |= 0x05; /* agc & aec */ else val &= 0xfa; @@ -960,8 +1025,10 @@ static void setexposure(struct gspca_dev *gspca_dev) u8 val; static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e}; + if (gspca_dev->ctrl_dis & (1 << EXPOSURE)) + return; sccb_write(gspca_dev, 0x10, /* aec[9:2] */ - expo[sd->exposure]); + expo[sd->ctrls[EXPOSURE].val]); val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); @@ -977,7 +1044,9 @@ static void setsharpness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; s8 val; - val = sd->sharpness; + if (gspca_dev->ctrl_dis & (1 << SHARPNESS)) + return; + val = sd->ctrls[SHARPNESS].val; if (val < 0) { /* auto */ val = sccb_read(gspca_dev, 0x42); /* com17 */ sccb_write(gspca_dev, 0xff, 0x00); @@ -1006,8 +1075,10 @@ static void setsatur(struct gspca_dev *gspca_dev) {0x48, 0x90} }; - val1 = matrix[sd->satur][0]; - val2 = matrix[sd->satur][1]; + if (gspca_dev->ctrl_dis & (1 << SATUR)) + return; + val1 = matrix[sd->ctrls[SATUR].val][0]; + val2 = matrix[sd->ctrls[SATUR].val][1]; val3 = val1 + val2; sccb_write(gspca_dev, 0x4f, val3); /* matrix coeff */ sccb_write(gspca_dev, 0x50, val3); @@ -1022,14 +1093,16 @@ static void setsatur(struct gspca_dev *gspca_dev) sccb_write(gspca_dev, 0x41, val1); } -static void setfreq(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; + if (gspca_dev->ctrl_dis & (1 << LIGHTFREQ)) + return; val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->freq == 0) { + if (sd->ctrls[LIGHTFREQ].val == 0) { sccb_write(gspca_dev, 0x13, val & 0xdf); return; } @@ -1037,7 +1110,7 @@ static void setfreq(struct gspca_dev *gspca_dev) val = sccb_read(gspca_dev, 0x42); /* com17 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->freq == 1) + if (sd->ctrls[LIGHTFREQ].val == 1) val |= 0x01; else val &= 0xfe; @@ -1049,34 +1122,19 @@ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = ov965x_mode; - cam->nmodes = ARRAY_SIZE(ov965x_mode); + gspca_dev->cam.ctrls = sd->ctrls; - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; #if AUTOGAIN_DEF != 0 - sd->autogain = AUTOGAIN_DEF; - gspca_dev->ctrl_inac |= (1 << EXPO_IDX); -#endif -#if EXPO_DEF != 0 - sd->exposure = EXPO_DEF; -#endif -#if SHARPNESS_DEF != 0 - sd->sharpness = SHARPNESS_DEF; + gspca_dev->ctrl_inac |= (1 << EXPOSURE); #endif - sd->satur = SATUR_DEF; - sd->freq = FREQ_DEF; - return 0; } /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; u16 sensor_id; /* reset bridge */ @@ -1099,68 +1157,117 @@ static int sd_init(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); /* initialize */ - reg_w_array(gspca_dev, bridge_init, - ARRAY_SIZE(bridge_init)); - sccb_w_array(gspca_dev, sensor_init, - ARRAY_SIZE(sensor_init)); - reg_w_array(gspca_dev, bridge_init_2, - ARRAY_SIZE(bridge_init_2)); - sccb_w_array(gspca_dev, sensor_init_2, - ARRAY_SIZE(sensor_init_2)); - reg_w(gspca_dev, 0xe0, 0x00); - reg_w(gspca_dev, 0xe0, 0x01); - set_led(gspca_dev, 0); - reg_w(gspca_dev, 0xe0, 0x00); + if ((sensor_id & 0xfff0) == 0x9650) { + sd->sensor = SENSOR_OV965x; + + gspca_dev->cam.cam_mode = ov965x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov965x_mode); + + reg_w_array(gspca_dev, bridge_init, + ARRAY_SIZE(bridge_init)); + sccb_w_array(gspca_dev, ov965x_init, + ARRAY_SIZE(ov965x_init)); + reg_w_array(gspca_dev, bridge_init_2, + ARRAY_SIZE(bridge_init_2)); + sccb_w_array(gspca_dev, ov965x_init_2, + ARRAY_SIZE(ov965x_init_2)); + reg_w(gspca_dev, 0xe0, 0x00); + reg_w(gspca_dev, 0xe0, 0x01); + set_led(gspca_dev, 0); + reg_w(gspca_dev, 0xe0, 0x00); + } else if ((sensor_id & 0xfff0) == 0x9710) { + const char *p; + int l; + + sd->sensor = SENSOR_OV971x; + + gspca_dev->cam.cam_mode = ov971x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov971x_mode); + + /* no control yet */ + gspca_dev->ctrl_dis = (1 << NCTRLS) - 1; + + gspca_dev->cam.bulk = 1; + gspca_dev->cam.bulk_size = 16384; + gspca_dev->cam.bulk_nurbs = 2; + + sccb_w_array(gspca_dev, ov971x_init, + ARRAY_SIZE(ov971x_init)); + + /* set video format on bridge processor */ + /* access bridge processor's video format registers at: 0x00 */ + reg_w(gspca_dev, 0x1c, 0x00); + /*set register: 0x00 is 'RAW8', 0x40 is 'YUV422' (YUYV?)*/ + reg_w(gspca_dev, 0x1d, 0x00); + + /* Will W. specific stuff + * set VSYNC to + * output (0x1f) if first webcam + * input (0x17) if 2nd or 3rd webcam */ + p = video_device_node_name(&gspca_dev->vdev); + l = strlen(p) - 1; + if (p[l] == '0') + reg_w(gspca_dev, 0x56, 0x1f); + else + reg_w(gspca_dev, 0x56, 0x17); + } else { + err("Unknown sensor %04x", sensor_id); + return -EINVAL; + } return gspca_dev->usb_err; } static int sd_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_OV971x) + return gspca_dev->usb_err; switch (gspca_dev->curr_mode) { case QVGA_MODE: /* 320x240 */ - sccb_w_array(gspca_dev, sensor_start_1_vga, - ARRAY_SIZE(sensor_start_1_vga)); + sccb_w_array(gspca_dev, ov965x_start_1_vga, + ARRAY_SIZE(ov965x_start_1_vga)); reg_w_array(gspca_dev, bridge_start_qvga, ARRAY_SIZE(bridge_start_qvga)); - sccb_w_array(gspca_dev, sensor_start_2_qvga, - ARRAY_SIZE(sensor_start_2_qvga)); + sccb_w_array(gspca_dev, ov965x_start_2_qvga, + ARRAY_SIZE(ov965x_start_2_qvga)); break; case VGA_MODE: /* 640x480 */ - sccb_w_array(gspca_dev, sensor_start_1_vga, - ARRAY_SIZE(sensor_start_1_vga)); + sccb_w_array(gspca_dev, ov965x_start_1_vga, + ARRAY_SIZE(ov965x_start_1_vga)); reg_w_array(gspca_dev, bridge_start_vga, ARRAY_SIZE(bridge_start_vga)); - sccb_w_array(gspca_dev, sensor_start_2_vga, - ARRAY_SIZE(sensor_start_2_vga)); + sccb_w_array(gspca_dev, ov965x_start_2_vga, + ARRAY_SIZE(ov965x_start_2_vga)); break; case SVGA_MODE: /* 800x600 */ - sccb_w_array(gspca_dev, sensor_start_1_svga, - ARRAY_SIZE(sensor_start_1_svga)); + sccb_w_array(gspca_dev, ov965x_start_1_svga, + ARRAY_SIZE(ov965x_start_1_svga)); reg_w_array(gspca_dev, bridge_start_svga, ARRAY_SIZE(bridge_start_svga)); - sccb_w_array(gspca_dev, sensor_start_2_svga, - ARRAY_SIZE(sensor_start_2_svga)); + sccb_w_array(gspca_dev, ov965x_start_2_svga, + ARRAY_SIZE(ov965x_start_2_svga)); break; case XGA_MODE: /* 1024x768 */ - sccb_w_array(gspca_dev, sensor_start_1_xga, - ARRAY_SIZE(sensor_start_1_xga)); + sccb_w_array(gspca_dev, ov965x_start_1_xga, + ARRAY_SIZE(ov965x_start_1_xga)); reg_w_array(gspca_dev, bridge_start_xga, ARRAY_SIZE(bridge_start_xga)); - sccb_w_array(gspca_dev, sensor_start_2_svga, - ARRAY_SIZE(sensor_start_2_svga)); + sccb_w_array(gspca_dev, ov965x_start_2_svga, + ARRAY_SIZE(ov965x_start_2_svga)); break; default: /* case SXGA_MODE: * 1280x1024 */ - sccb_w_array(gspca_dev, sensor_start_1_sxga, - ARRAY_SIZE(sensor_start_1_sxga)); + sccb_w_array(gspca_dev, ov965x_start_1_sxga, + ARRAY_SIZE(ov965x_start_1_sxga)); reg_w_array(gspca_dev, bridge_start_sxga, ARRAY_SIZE(bridge_start_sxga)); - sccb_w_array(gspca_dev, sensor_start_2_sxga, - ARRAY_SIZE(sensor_start_2_sxga)); + sccb_w_array(gspca_dev, ov965x_start_2_sxga, + ARRAY_SIZE(ov965x_start_2_sxga)); break; } - setfreq(gspca_dev); + setlightfreq(gspca_dev); setautogain(gspca_dev); setbrightness(gspca_dev); setcontrast(gspca_dev); @@ -1198,9 +1305,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, __u32 this_pts; u8 this_fid; int remaining_len = len; + int payload_len; + payload_len = gspca_dev->cam.bulk ? 2048 : 2040; do { - len = min(remaining_len, 2040); + len = min(remaining_len, payload_len); /* Payloads are prefixed with a UVC-style header. We consider a frame to start when the FID toggles, or the PTS @@ -1262,138 +1371,6 @@ scan_next: } while (remaining_len > 0); } -/* controls */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - - if (gspca_dev->streaming) { - if (val) - gspca_dev->ctrl_inac |= (1 << EXPO_IDX); - else - gspca_dev->ctrl_inac &= ~(1 << EXPO_IDX); - setautogain(gspca_dev); - } - return gspca_dev->usb_err; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->satur = val; - if (gspca_dev->streaming) - setsatur(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->satur; - return 0; -} -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->freq = val; - if (gspca_dev->streaming) - setfreq(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freq; - return 0; -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { @@ -1419,7 +1396,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, static const struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), + .nctrls = NCTRLS, .config = sd_config, .init = sd_init, .start = sd_start, @@ -1430,6 +1407,7 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x05a9, 0x8065)}, {USB_DEVICE(0x06f8, 0x3003)}, {} }; diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index 81739a2..1600df1 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -23,6 +23,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "pac207" #include <linux/input.h> @@ -178,8 +180,8 @@ static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, 0x00, index, gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT); if (err < 0) - err("Failed to write registers to index 0x%04X, error %d)", - index, err); + pr_err("Failed to write registers to index 0x%04X, error %d\n", + index, err); return err; } @@ -194,8 +196,8 @@ static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, value, index, NULL, 0, PAC207_CTRL_TIMEOUT); if (err) - err("Failed to write a register (index 0x%04X," - " value 0x%02X, error %d)", index, value, err); + pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n", + index, value, err); return err; } @@ -210,8 +212,8 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) 0x00, index, gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT); if (res < 0) { - err("Failed to read a register (index 0x%04X, error %d)", - index, res); + pr_err("Failed to read a register (index 0x%04X, error %d)\n", + index, res); return res; } diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 5615d7b..ae433ef 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -61,6 +61,8 @@ 3 | 0x21 | sethvflip() */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "pac7302" #include <linux/input.h> @@ -408,8 +410,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_w_buf failed index 0x%02x, error %d", - index, ret); + pr_err("reg_w_buf failed index 0x%02x, error %d\n", + index, ret); gspca_dev->usb_err = ret; } } @@ -431,8 +433,8 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w() failed index 0x%02x, value 0x%02x, error %d", - index, value, ret); + pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n", + index, value, ret); gspca_dev->usb_err = ret; } } @@ -466,9 +468,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w_page() failed index 0x%02x, " - "value 0x%02x, error %d", - index, page[index], ret); + pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n", + index, page[index], ret); gspca_dev->usb_err = ret; break; } @@ -1189,6 +1190,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2620)}, {USB_DEVICE(0x093a, 0x2621)}, {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2625)}, {USB_DEVICE(0x093a, 0x2626)}, @@ -1196,6 +1198,8 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x262a)}, {USB_DEVICE(0x093a, 0x262c)}, + {USB_DEVICE(0x145f, 0x013c)}, + {USB_DEVICE(0x1ae7, 0x2001)}, /* SpeedLink Snappy Mic SL-6825-SBK */ {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index f8801b5..7509d05 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -49,6 +49,8 @@ for max gain, 0x14 for minimal gain. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "pac7311" #include <linux/input.h> @@ -276,8 +278,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_w_buf() failed index 0x%02x, error %d", - index, ret); + pr_err("reg_w_buf() failed index 0x%02x, error %d\n", + index, ret); gspca_dev->usb_err = ret; } } @@ -299,8 +301,8 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w() failed index 0x%02x, value 0x%02x, error %d", - index, value, ret); + pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n", + index, value, ret); gspca_dev->usb_err = ret; } } @@ -334,9 +336,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w_page() failed index 0x%02x, " - "value 0x%02x, error %d", - index, page[index], ret); + pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n", + index, page[index], ret); gspca_dev->usb_err = ret; break; } diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c index 4271f86..48aae39 100644 --- a/drivers/media/video/gspca/sn9c2028.c +++ b/drivers/media/video/gspca/sn9c2028.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sn9c2028" #include "gspca.h" @@ -75,8 +77,8 @@ static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 2, 0, gspca_dev->usb_buf, 6, 500); if (rc < 0) { - err("command write [%02x] error %d", - gspca_dev->usb_buf[0], rc); + pr_err("command write [%02x] error %d\n", + gspca_dev->usb_buf[0], rc); return rc; } @@ -93,7 +95,7 @@ static int sn9c2028_read1(struct gspca_dev *gspca_dev) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 1, 0, gspca_dev->usb_buf, 1, 500); if (rc != 1) { - err("read1 error %d", rc); + pr_err("read1 error %d\n", rc); return (rc < 0) ? rc : -EIO; } PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]); @@ -109,7 +111,7 @@ static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 4, 0, gspca_dev->usb_buf, 4, 500); if (rc != 4) { - err("read4 error %d", rc); + pr_err("read4 error %d\n", rc); return (rc < 0) ? rc : -EIO; } memcpy(reading, gspca_dev->usb_buf, 4); @@ -131,7 +133,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) for (i = 0; i < 256 && status < 2; i++) status = sn9c2028_read1(gspca_dev); if (status != 2) { - err("long command status read error %d", status); + pr_err("long command status read error %d\n", status); return (status < 0) ? status : -EIO; } @@ -638,7 +640,7 @@ static int sd_start(struct gspca_dev *gspca_dev) err_code = start_vivitar_cam(gspca_dev); break; default: - err("Starting unknown camera, please report this"); + pr_err("Starting unknown camera, please report this\n"); return -ENXIO; } diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index c431900..509e202 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/input.h> #include "gspca.h" @@ -1123,7 +1125,7 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) length, 500); if (unlikely(result < 0 || result != length)) { - err("Read register failed 0x%02X", reg); + pr_err("Read register failed 0x%02X\n", reg); return -EIO; } return 0; @@ -1144,7 +1146,7 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg, length, 500); if (unlikely(result < 0 || result != length)) { - err("Write register failed index 0x%02X", reg); + pr_err("Write register failed index 0x%02X\n", reg); return -EIO; } return 0; @@ -1275,14 +1277,14 @@ static int ov9650_init_sensor(struct gspca_dev *gspca_dev) return -EINVAL; if (id != 0x7fa2) { - err("sensor id for ov9650 doesn't match (0x%04x)", id); + pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id); return -ENODEV; } for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { if (i2c_w1(gspca_dev, ov9650_init[i].reg, ov9650_init[i].val) < 0) { - err("OV9650 sensor initialization failed"); + pr_err("OV9650 sensor initialization failed\n"); return -ENODEV; } } @@ -1299,7 +1301,7 @@ static int ov9655_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { if (i2c_w1(gspca_dev, ov9655_init[i].reg, ov9655_init[i].val) < 0) { - err("OV9655 sensor initialization failed"); + pr_err("OV9655 sensor initialization failed\n"); return -ENODEV; } } @@ -1318,7 +1320,7 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { if (i2c_w1(gspca_dev, soi968_init[i].reg, soi968_init[i].val) < 0) { - err("SOI968 sensor initialization failed"); + pr_err("SOI968 sensor initialization failed\n"); return -ENODEV; } } @@ -1338,7 +1340,7 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { if (i2c_w1(gspca_dev, ov7660_init[i].reg, ov7660_init[i].val) < 0) { - err("OV7660 sensor initialization failed"); + pr_err("OV7660 sensor initialization failed\n"); return -ENODEV; } } @@ -1355,7 +1357,7 @@ static int ov7670_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { if (i2c_w1(gspca_dev, ov7670_init[i].reg, ov7670_init[i].val) < 0) { - err("OV7670 sensor initialization failed"); + pr_err("OV7670 sensor initialization failed\n"); return -ENODEV; } } @@ -1379,14 +1381,14 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { if (i2c_w2(gspca_dev, mt9v011_init[i].reg, mt9v011_init[i].val) < 0) { - err("MT9V011 sensor initialization failed"); + pr_err("MT9V011 sensor initialization failed\n"); return -ENODEV; } } sd->hstart = 2; sd->vstart = 2; sd->sensor = SENSOR_MT9V011; - info("MT9V011 sensor detected"); + pr_info("MT9V011 sensor detected\n"); return 0; } @@ -1397,7 +1399,7 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { if (i2c_w2(gspca_dev, mt9v111_init[i].reg, mt9v111_init[i].val) < 0) { - err("MT9V111 sensor initialization failed"); + pr_err("MT9V111 sensor initialization failed\n"); return -ENODEV; } } @@ -1407,7 +1409,7 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) sd->hstart = 2; sd->vstart = 2; sd->sensor = SENSOR_MT9V111; - info("MT9V111 sensor detected"); + pr_info("MT9V111 sensor detected\n"); return 0; } @@ -1422,14 +1424,14 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { if (i2c_w2(gspca_dev, mt9v112_init[i].reg, mt9v112_init[i].val) < 0) { - err("MT9V112 sensor initialization failed"); + pr_err("MT9V112 sensor initialization failed\n"); return -ENODEV; } } sd->hstart = 6; sd->vstart = 2; sd->sensor = SENSOR_MT9V112; - info("MT9V112 sensor detected"); + pr_info("MT9V112 sensor detected\n"); return 0; } @@ -1443,7 +1445,7 @@ static int mt9m112_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) { if (i2c_w2(gspca_dev, mt9m112_init[i].reg, mt9m112_init[i].val) < 0) { - err("MT9M112 sensor initialization failed"); + pr_err("MT9M112 sensor initialization failed\n"); return -ENODEV; } } @@ -1461,7 +1463,7 @@ static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { if (i2c_w2(gspca_dev, mt9m111_init[i].reg, mt9m111_init[i].val) < 0) { - err("MT9M111 sensor initialization failed"); + pr_err("MT9M111 sensor initialization failed\n"); return -ENODEV; } } @@ -1485,20 +1487,20 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) switch (id) { case 0x8411: case 0x8421: - info("MT9M001 color sensor detected"); + pr_info("MT9M001 color sensor detected\n"); break; case 0x8431: - info("MT9M001 mono sensor detected"); + pr_info("MT9M001 mono sensor detected\n"); break; default: - err("No MT9M001 chip detected, ID = %x\n", id); + pr_err("No MT9M001 chip detected, ID = %x\n\n", id); return -ENODEV; } for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { if (i2c_w2(gspca_dev, mt9m001_init[i].reg, mt9m001_init[i].val) < 0) { - err("MT9M001 sensor initialization failed"); + pr_err("MT9M001 sensor initialization failed\n"); return -ENODEV; } } @@ -1517,7 +1519,7 @@ static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { if (i2c_w1(gspca_dev, hv7131r_init[i].reg, hv7131r_init[i].val) < 0) { - err("HV7131R Sensor initialization failed"); + pr_err("HV7131R Sensor initialization failed\n"); return -ENODEV; } } @@ -2103,7 +2105,7 @@ static int sd_init(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { value = bridge_init[i][1]; if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { - err("Device initialization failed"); + pr_err("Device initialization failed\n"); return -ENODEV; } } @@ -2114,7 +2116,7 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x1006, 0x20); if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { - err("Device initialization failed"); + pr_err("Device initialization failed\n"); return -ENODEV; } @@ -2122,27 +2124,27 @@ static int sd_init(struct gspca_dev *gspca_dev) case SENSOR_OV9650: if (ov9650_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV9650 sensor detected"); + pr_info("OV9650 sensor detected\n"); break; case SENSOR_OV9655: if (ov9655_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV9655 sensor detected"); + pr_info("OV9655 sensor detected\n"); break; case SENSOR_SOI968: if (soi968_init_sensor(gspca_dev) < 0) return -ENODEV; - info("SOI968 sensor detected"); + pr_info("SOI968 sensor detected\n"); break; case SENSOR_OV7660: if (ov7660_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV7660 sensor detected"); + pr_info("OV7660 sensor detected\n"); break; case SENSOR_OV7670: if (ov7670_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV7670 sensor detected"); + pr_info("OV7670 sensor detected\n"); break; case SENSOR_MT9VPRB: if (mt9v_init_sensor(gspca_dev) < 0) @@ -2151,12 +2153,12 @@ static int sd_init(struct gspca_dev *gspca_dev) case SENSOR_MT9M111: if (mt9m111_init_sensor(gspca_dev) < 0) return -ENODEV; - info("MT9M111 sensor detected"); + pr_info("MT9M111 sensor detected\n"); break; case SENSOR_MT9M112: if (mt9m112_init_sensor(gspca_dev) < 0) return -ENODEV; - info("MT9M112 sensor detected"); + pr_info("MT9M112 sensor detected\n"); break; case SENSOR_MT9M001: if (mt9m001_init_sensor(gspca_dev) < 0) @@ -2165,10 +2167,10 @@ static int sd_init(struct gspca_dev *gspca_dev) case SENSOR_HV7131R: if (hv7131r_init_sensor(gspca_dev) < 0) return -ENODEV; - info("HV7131R sensor detected"); + pr_info("HV7131R sensor detected\n"); break; default: - info("Unsupported Sensor"); + pr_info("Unsupported Sensor\n"); return -ENODEV; } @@ -2263,19 +2265,19 @@ static int sd_start(struct gspca_dev *gspca_dev) switch (mode & SCALE_MASK) { case SCALE_1280x1024: scale = 0xc0; - info("Set 1280x1024"); + pr_info("Set 1280x1024\n"); break; case SCALE_640x480: scale = 0x80; - info("Set 640x480"); + pr_info("Set 640x480\n"); break; case SCALE_320x240: scale = 0x90; - info("Set 320x240"); + pr_info("Set 320x240\n"); break; case SCALE_160x120: scale = 0xa0; - info("Set 160x120"); + pr_info("Set 160x120\n"); break; } @@ -2513,12 +2515,13 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)}, {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)}, {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)}, - {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)}, {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)}, {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)}, {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)}, {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)}, {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0x0458, 0x7045), SN9C20X(MT9M112, 0x5d, LED_REVERSE)}, {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)}, {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)}, {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)}, diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 81b8a60..c746bf1 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1,7 +1,7 @@ /* * Sonix sn9c102p sn9c105 sn9c120 (jpeg) subdriver * - * Copyright (C) 2009-2010 Jean-François Moine <http://moinejf.free.fr> + * Copyright (C) 2009-2011 Jean-François Moine <http://moinejf.free.fr> * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr * * This program is free software; you can redistribute it and/or modify @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sonixj" #include <linux/input.h> @@ -136,7 +138,7 @@ static void setillum(struct gspca_dev *gspca_dev); static void setfreq(struct gspca_dev *gspca_dev); static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { +[BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -157,7 +159,7 @@ static const struct ctrl sd_ctrls[NCTRLS] = { #define CONTRAST_MAX 127 .maximum = CONTRAST_MAX, .step = 1, - .default_value = 63, + .default_value = 20, }, .set_control = setcontrast }, @@ -737,7 +739,7 @@ static const u8 mi0360_sensor_init[][8] = { {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10}, - {0xd1, 0x5d, 0x2f, 0xf7, 0xB0, 0x00, 0x04, 0x10}, + {0xd1, 0x5d, 0x2f, 0xf7, 0xb0, 0x00, 0x04, 0x10}, {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10}, {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10}, @@ -1277,7 +1279,7 @@ static const u8 soi768_sensor_param1[][8] = { /* global gain ? : 07 - change with 0x15 at the end */ {0xa1, 0x21, 0x10, 0x3f, 0x00, 0x00, 0x00, 0x10}, /* ???? : 063f */ {0xa1, 0x21, 0x04, 0x06, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x2d, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x2d, 0x63, 0x03, 0x00, 0x00, 0x10}, /* exposure ? : 0200 - change with 0x1e at the end */ {} }; @@ -1395,7 +1397,7 @@ static void reg_r(struct gspca_dev *gspca_dev, return; #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -1408,7 +1410,7 @@ static void reg_r(struct gspca_dev *gspca_dev, 500); PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1432,7 +1434,7 @@ static void reg_w1(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w1 err %d", ret); + pr_err("reg_w1 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1449,7 +1451,7 @@ static void reg_w(struct gspca_dev *gspca_dev, value, buffer[0], buffer[1]); #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); + pr_err("reg_w: buffer overflow\n"); return; } #endif @@ -1462,7 +1464,7 @@ static void reg_w(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1502,7 +1504,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) gspca_dev->usb_buf, 8, 500); if (ret < 0) { - err("i2c_w1 err %d", ret); + pr_err("i2c_w1 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1527,7 +1529,7 @@ static void i2c_w8(struct gspca_dev *gspca_dev, 500); msleep(2); if (ret < 0) { - err("i2c_w8 err %d", ret); + pr_err("i2c_w8 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1591,7 +1593,7 @@ static void hv7131r_probe(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor HV7131R found"); return; } - warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x", + pr_warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x\n", gspca_dev->usb_buf[0], gspca_dev->usb_buf[1], gspca_dev->usb_buf[2]); } @@ -1710,7 +1712,7 @@ static void ov7648_probe(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_PO1030; return; } - err("Unknown sensor %04x", val); + pr_err("Unknown sensor %04x\n", val); } /* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */ @@ -1748,7 +1750,7 @@ static void po2030n_probe(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor po2030n"); /* sd->sensor = SENSOR_PO2030N; */ } else { - err("Unknown sensor ID %04x", val); + pr_err("Unknown sensor ID %04x\n", val); } } @@ -2006,8 +2008,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) case SENSOR_OM6802: expo = brightness << 2; sd->exposure = setexposure(gspca_dev, expo); - k2 = brightness >> 3; - break; + return; /* Y offset already set */ } reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */ @@ -2019,13 +2020,13 @@ static void setcontrast(struct gspca_dev *gspca_dev) u8 k2; u8 contrast[6]; - k2 = sd->ctrls[CONTRAST].val * 0x30 / (CONTRAST_MAX + 1) - + 0x10; /* 10..40 */ + k2 = sd->ctrls[CONTRAST].val * 37 / (CONTRAST_MAX + 1) + + 37; /* 37..73 */ contrast[0] = (k2 + 1) / 2; /* red */ contrast[1] = 0; contrast[2] = k2; /* green */ contrast[3] = 0; - contrast[4] = (k2 + 1) / 5; /* blue */ + contrast[4] = k2 / 5; /* blue */ contrast[5] = 0; reg_w(gspca_dev, 0x84, contrast, sizeof contrast); } @@ -2386,7 +2387,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x01, 0x22); msleep(100); reg01 = SCL_SEL_OD | S_PDN_INV; - reg17 &= MCK_SIZE_MASK; + reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x04; /* clock / 4 */ break; } @@ -2507,9 +2508,7 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case SENSOR_HV7131R: case SENSOR_MI0360: - if (mode) - reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */ - else + if (!mode) reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */ reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x01; /* clock / 1 */ @@ -2532,6 +2531,10 @@ static int sd_start(struct gspca_dev *gspca_dev) if (!mode) { /* if 640x480 */ reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x04; /* clock / 4 */ + } else { + reg01 &= ~SYS_SEL_48M; /* clk 24Mz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x02; /* clock / 2 */ } break; case SENSOR_OV7630: diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index 76c006b..6956731 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -1,7 +1,7 @@ /* * spca1528 subdriver * - * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) + * Copyright (C) 2010-2011 Jean-Francois Moine (http://moinejf.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 @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca1528" #include "gspca.h" @@ -171,7 +173,7 @@ static void reg_r(struct gspca_dev *gspca_dev, PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -193,7 +195,7 @@ static void reg_w(struct gspca_dev *gspca_dev, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -217,21 +219,23 @@ static void reg_wb(struct gspca_dev *gspca_dev, value, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } static void wait_status_0(struct gspca_dev *gspca_dev) { - int i; + int i, w; - i = 20; + i = 16; + w = 0; do { reg_r(gspca_dev, 0x21, 0x0000, 1); if (gspca_dev->usb_buf[0] == 0) return; - msleep(30); + w += 15; + msleep(w); } while (--i > 0); PDEBUG(D_ERR, "wait_status_0 timeout"); gspca_dev->usb_err = -ETIME; @@ -307,8 +311,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->color = COLOR_DEF; sd->sharpness = SHARPNESS_DEF; - gspca_dev->nbalt = 4; /* use alternate setting 3 */ - return 0; } @@ -347,8 +349,12 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode); reg_r(gspca_dev, 0x25, 0x0004, 1); - reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); + reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); /* 420 */ reg_r(gspca_dev, 0x27, 0x0000, 1); + +/* not useful.. + gspca_dev->alt = 4; * use alternate setting 3 */ + return gspca_dev->usb_err; } @@ -361,8 +367,8 @@ static int sd_start(struct gspca_dev *gspca_dev) jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ - /* the JPEG quality seems to be 82% */ - jpeg_set_qual(sd->jpeg_hdr, 82); + /* the JPEG quality shall be 85% */ + jpeg_set_qual(sd->jpeg_hdr, 85); /* set the controls */ setbrightness(gspca_dev); @@ -377,7 +383,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* start the capture */ wait_status_0(gspca_dev); - reg_w(gspca_dev, 0x31, 0x0000, 0x0004); + reg_w(gspca_dev, 0x31, 0x0000, 0x0004); /* start request */ wait_status_1(gspca_dev); wait_status_0(gspca_dev); msleep(200); @@ -390,7 +396,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { /* stop the capture */ wait_status_0(gspca_dev); - reg_w(gspca_dev, 0x31, 0x0000, 0x0000); + reg_w(gspca_dev, 0x31, 0x0000, 0x0000); /* stop request */ wait_status_1(gspca_dev); wait_status_0(gspca_dev); } diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 3e76951..bb82c94 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca500" #include "gspca.h" @@ -396,7 +398,7 @@ static int reg_w(struct gspca_dev *gspca_dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } @@ -418,7 +420,7 @@ static int reg_r_12(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, length, 500); /* timeout */ if (ret < 0) { - err("reg_r_12 err %d", ret); + pr_err("reg_r_12 err %d\n", ret); return ret; } return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index f7ef282..7aaac72 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca501" #include "gspca.h" @@ -1852,7 +1854,7 @@ static int reg_write(struct usb_device *dev, PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x", req, index, value); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index e5bf865..16722dc 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca505" #include "gspca.h" @@ -578,7 +580,7 @@ static int reg_write(struct usb_device *dev, PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", req, index, value, ret); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } @@ -685,8 +687,8 @@ static int sd_start(struct gspca_dev *gspca_dev) return ret; } if (ret != 0x0101) { - err("After vector read returns 0x%04x should be 0x0101", - ret); + pr_err("After vector read returns 0x%04x should be 0x0101\n", + ret); } ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a); diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 9d0b460..a44fe3d 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca508" #include "gspca.h" @@ -1275,7 +1277,7 @@ static int reg_write(struct usb_device *dev, PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x", index, value); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } @@ -1297,7 +1299,7 @@ static int reg_read(struct gspca_dev *gspca_dev, PDEBUG(D_USBI, "reg read i:%04x --> %02x", index, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_read err %d", ret); + pr_err("reg_read err %d\n", ret); return ret; } return gspca_dev->usb_buf[0]; diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index e836e77..c82fd53 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca561" #include <linux/input.h> @@ -315,7 +317,7 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) value, index, NULL, 0, 500); PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); } static void write_vector(struct gspca_dev *gspca_dev, diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 5ba96af..df805f7 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c @@ -33,6 +33,8 @@ * drivers. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sq905" #include <linux/workqueue.h> @@ -123,8 +125,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index) SQ905_COMMAND, index, gspca_dev->usb_buf, 1, SQ905_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -135,8 +136,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index) SQ905_PING, 0, gspca_dev->usb_buf, 1, SQ905_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed 2 (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed 2 (%d)\n", __func__, ret); return ret; } @@ -158,7 +158,7 @@ static int sq905_ack_frame(struct gspca_dev *gspca_dev) SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1, SQ905_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -186,7 +186,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) if (need_lock) mutex_unlock(&gspca_dev->usb_lock); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } ret = usb_bulk_msg(gspca_dev->dev, @@ -195,8 +195,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) /* successful, it returns 0, otherwise negative */ if (ret < 0 || act_len != size) { - err("bulk read fail (%d) len %d/%d", - ret, act_len, size); + pr_err("bulk read fail (%d) len %d/%d\n", ret, act_len, size); return -EIO; } return 0; @@ -226,7 +225,7 @@ static void sq905_dostream(struct work_struct *work) buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); if (!buffer) { - err("Couldn't allocate USB buffer"); + pr_err("Couldn't allocate USB buffer\n"); goto quit_stream; } diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c index 457563b..c2c0560 100644 --- a/drivers/media/video/gspca/sq905c.c +++ b/drivers/media/video/gspca/sq905c.c @@ -27,6 +27,8 @@ * and may contain code fragments from it. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sq905c" #include <linux/workqueue.h> @@ -95,8 +97,7 @@ static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index) command, index, NULL, 0, SQ905C_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -115,8 +116,7 @@ static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index, command, index, gspca_dev->usb_buf, size, SQ905C_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -146,7 +146,7 @@ static void sq905c_dostream(struct work_struct *work) buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); if (!buffer) { - err("Couldn't allocate USB buffer"); + pr_err("Couldn't allocate USB buffer\n"); goto quit_stream; } diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c index 8215d5d..e4255b4 100644 --- a/drivers/media/video/gspca/sq930x.c +++ b/drivers/media/video/gspca/sq930x.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sq930x" #include "gspca.h" @@ -468,7 +470,7 @@ static void reg_r(struct gspca_dev *gspca_dev, value, 0, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_r %04x failed %d", value, ret); + pr_err("reg_r %04x failed %d\n", value, ret); gspca_dev->usb_err = ret; } } @@ -488,7 +490,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 500); msleep(30); if (ret < 0) { - err("reg_w %04x %04x failed %d", value, index, ret); + pr_err("reg_w %04x %04x failed %d\n", value, index, ret); gspca_dev->usb_err = ret; } } @@ -511,7 +513,7 @@ static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, 1000); msleep(30); if (ret < 0) { - err("reg_wb %04x %04x failed %d", value, index, ret); + pr_err("reg_wb %04x %04x failed %d\n", value, index, ret); gspca_dev->usb_err = ret; } } @@ -556,7 +558,7 @@ static void i2c_write(struct sd *sd, gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 500); if (ret < 0) { - err("i2c_write failed %d", ret); + pr_err("i2c_write failed %d\n", ret); gspca_dev->usb_err = ret; } } @@ -575,7 +577,7 @@ static void ucbus_write(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if ((batchsize - 1) * 3 > USB_BUF_SZ) { - err("Bug: usb_buf overflow"); + pr_err("Bug: usb_buf overflow\n"); gspca_dev->usb_err = -ENOMEM; return; } @@ -612,7 +614,7 @@ static void ucbus_write(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 500); if (ret < 0) { - err("ucbus_write failed %d", ret); + pr_err("ucbus_write failed %d\n", ret); gspca_dev->usb_err = ret; return; } @@ -688,7 +690,7 @@ static void cmos_probe(struct gspca_dev *gspca_dev) break; } if (i >= ARRAY_SIZE(probe_order)) { - err("Unknown sensor"); + pr_err("Unknown sensor\n"); gspca_dev->usb_err = -EINVAL; return; } @@ -696,7 +698,8 @@ static void cmos_probe(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_OV7660: case SENSOR_OV9630: - err("Sensor %s not yet treated", sensor_tb[sd->sensor].name); + pr_err("Sensor %s not yet treated\n", + sensor_tb[sd->sensor].name); gspca_dev->usb_err = -EINVAL; break; } @@ -1091,7 +1094,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev) gspca_dev->cam.bulk_nurbs = 1; ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); if (ret < 0) - err("sd_dq_callback() err %d", ret); + pr_err("sd_dq_callback() err %d\n", ret); /* wait a little time, otherwise the webcam crashes */ msleep(100); diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 7637477..42a7a28 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "stk014" #include "gspca.h" @@ -137,7 +139,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; return 0; } @@ -162,7 +164,7 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -192,7 +194,7 @@ static void rcv_val(struct gspca_dev *gspca_dev, &alen, 500); /* timeout in milliseconds */ if (ret < 0) { - err("rcv_val err %d", ret); + pr_err("rcv_val err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -235,7 +237,7 @@ static void snd_val(struct gspca_dev *gspca_dev, &alen, 500); /* timeout in milliseconds */ if (ret < 0) { - err("snd_val err %d", ret); + pr_err("snd_val err %d\n", ret); gspca_dev->usb_err = ret; } else { if (ads == 0x003f08) { @@ -315,7 +317,7 @@ static int sd_init(struct gspca_dev *gspca_dev) ret = reg_r(gspca_dev, 0x0740); if (gspca_dev->usb_err >= 0) { if (ret != 0xff) { - err("init reg: 0x%02x", ret); + pr_err("init reg: 0x%02x\n", ret); gspca_dev->usb_err = -EIO; } } @@ -349,8 +351,8 @@ static int sd_start(struct gspca_dev *gspca_dev) gspca_dev->iface, gspca_dev->alt); if (ret < 0) { - err("set intf %d %d failed", - gspca_dev->iface, gspca_dev->alt); + pr_err("set intf %d %d failed\n", + gspca_dev->iface, gspca_dev->alt); gspca_dev->usb_err = ret; goto out; } diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c index e2ef41c..4dcc7e3 100644 --- a/drivers/media/video/gspca/stv0680.c +++ b/drivers/media/video/gspca/stv0680.c @@ -27,6 +27,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "stv0680" #include "gspca.h" @@ -79,7 +81,7 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val, val, 0, gspca_dev->usb_buf, size, 500); if ((ret < 0) && (req != 0x0a)) - err("usb_control_msg error %i, request = 0x%x, error = %i", + pr_err("usb_control_msg error %i, request = 0x%x, error = %i\n", set, req, ret); return ret; @@ -236,7 +238,7 @@ static int sd_config(struct gspca_dev *gspca_dev, if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 || gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) { - err("Could not get descriptor 0100."); + pr_err("Could not get descriptor 0100\n"); return stv0680_handle_error(gspca_dev, -EIO); } diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile index 2f3c3a6..5b318fa 100644 --- a/drivers/media/video/gspca/stv06xx/Makefile +++ b/drivers/media/video/gspca/stv06xx/Makefile @@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \ stv06xx_pb0100.o \ stv06xx_st6422.o -EXTRA_CFLAGS += -Idrivers/media/video/gspca +ccflags-y += -Idrivers/media/video/gspca diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index abf1658..b1fca7d 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -27,6 +27,8 @@ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/input.h> #include "stv06xx_sensor.h" @@ -189,7 +191,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, STV06XX_URB_MSG_TIMEOUT); if (err < 0) { - err("I2C: Read error writing address: %d", err); + pr_err("I2C: Read error writing address: %d\n", err); return err; } @@ -213,14 +215,14 @@ static void stv06xx_dump_bridge(struct sd *sd) int i; u8 data, buf; - info("Dumping all stv06xx bridge registers"); + pr_info("Dumping all stv06xx bridge registers\n"); for (i = 0x1400; i < 0x160f; i++) { stv06xx_read_bridge(sd, i, &data); - info("Read 0x%x from address 0x%x", data, i); + pr_info("Read 0x%x from address 0x%x\n", data, i); } - info("Testing stv06xx bridge registers for writability"); + pr_info("Testing stv06xx bridge registers for writability\n"); for (i = 0x1400; i < 0x160f; i++) { stv06xx_read_bridge(sd, i, &data); buf = data; @@ -228,12 +230,12 @@ static void stv06xx_dump_bridge(struct sd *sd) stv06xx_write_bridge(sd, i, 0xff); stv06xx_read_bridge(sd, i, &data); if (data == 0xff) - info("Register 0x%x is read/write", i); + pr_info("Register 0x%x is read/write\n", i); else if (data != buf) - info("Register 0x%x is read/write," - " but only partially", i); + pr_info("Register 0x%x is read/write, but only partially\n", + i); else - info("Register 0x%x is read-only", i); + pr_info("Register 0x%x is read-only\n", i); stv06xx_write_bridge(sd, i, buf); } diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index e0f63c5..d270a59 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h @@ -37,6 +37,8 @@ #define STV_ISOC_ENDPOINT_ADDR 0x81 +#define STV_R 0x0509 + #define STV_REG23 0x0423 /* Control registers of the STV0600 ASIC */ @@ -61,7 +63,9 @@ /* Refers to the CIF 352x288 and QCIF 176x144 */ /* 1: 288 lines, 2: 144 lines */ -#define STV_Y_CTRL 0x15c3 +#define STV_Y_CTRL 0x15c3 + +#define STV_RESET 0x1620 /* 0xa: 352 columns, 0x6: 176 columns */ #define STV_X_CTRL 0x1680 diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index b815685..a8698b7 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -28,6 +28,8 @@ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_hdcs.h" static const struct ctrl hdcs1x00_ctrl[] = { @@ -428,7 +430,7 @@ static int hdcs_probe_1x00(struct sd *sd) if (ret < 0 || sensor != 0x08) return -ENODEV; - info("HDCS-1000/1100 sensor detected"); + pr_info("HDCS-1000/1100 sensor detected\n"); sd->gspca_dev.cam.cam_mode = hdcs1x00_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode); @@ -487,7 +489,7 @@ static int hdcs_probe_1020(struct sd *sd) if (ret < 0 || sensor != 0x10) return -ENODEV; - info("HDCS-1020 sensor detected"); + pr_info("HDCS-1020 sensor detected\n"); sd->gspca_dev.cam.cam_mode = hdcs1020_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode); @@ -601,11 +603,11 @@ static int hdcs_dump(struct sd *sd) { u16 reg, val; - info("Dumping sensor registers:"); + pr_info("Dumping sensor registers:\n"); for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { stv06xx_read_sensor(sd, reg, &val); - info("reg 0x%02x = 0x%02x", reg, val); + pr_info("reg 0x%02x = 0x%02x\n", reg, val); } return 0; } diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c index 75a5b9c..26f14fc 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c @@ -44,6 +44,8 @@ * PB_CFILLIN = R5 = 0x0E (14 dec) : Sets the frame rate */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_pb0100.h" static const struct ctrl pb0100_ctrl[] = { @@ -190,7 +192,7 @@ static int pb0100_probe(struct sd *sd) if (!sensor_settings) return -ENOMEM; - info("Photobit pb0100 sensor detected"); + pr_info("Photobit pb0100 sensor detected\n"); sd->gspca_dev.cam.cam_mode = pb0100_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode); diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c index 8a456de..9940e03 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c @@ -26,6 +26,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_st6422.h" /* controls */ @@ -136,7 +138,7 @@ static int st6422_probe(struct sd *sd) if (sd->bridge != BRIDGE_ST6422) return -ENODEV; - info("st6422 sensor detected"); + pr_info("st6422 sensor detected\n"); sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL); if (!sensor_settings) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index f839843..a5c69d9 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -27,6 +27,8 @@ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_vv6410.h" static struct v4l2_pix_format vv6410_mode[] = { @@ -112,7 +114,7 @@ static int vv6410_probe(struct sd *sd) return -ENODEV; if (data == 0x19) { - info("vv6410 sensor detected"); + pr_info("vv6410 sensor detected\n"); sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32), GFP_KERNEL); @@ -138,18 +140,7 @@ static int vv6410_init(struct sd *sd) s32 *sensor_settings = sd->sensor_priv; for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { - /* if NULL then len contains single value */ - if (stv_bridge_init[i].data == NULL) { - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start, - stv_bridge_init[i].len); - } else { - int j; - for (j = 0; j < stv_bridge_init[i].len; j++) - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start + j, - stv_bridge_init[i].data[j]); - } + stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data); } if (err < 0) @@ -183,15 +174,6 @@ static int vv6410_start(struct sd *sd) struct cam *cam = &sd->gspca_dev.cam; u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; - if (priv & VV6410_CROP_TO_QVGA) { - PDEBUG(D_CONF, "Cropping to QVGA"); - stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); - } else { - stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); - } - if (priv & VV6410_SUBSAMPLE) { PDEBUG(D_CONF, "Enabling subsampling"); stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); @@ -201,8 +183,8 @@ static int vv6410_start(struct sd *sd) } else { stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00); - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); } /* Turn on LED */ @@ -242,11 +224,11 @@ static int vv6410_dump(struct sd *sd) u8 i; int err = 0; - info("Dumping all vv6410 sensor registers"); + pr_info("Dumping all vv6410 sensor registers\n"); for (i = 0; i < 0xff && !err; i++) { u16 data; err = stv06xx_read_sensor(sd, i, &data); - info("Register 0x%x contained 0x%x", i, data); + pr_info("Register 0x%x contained 0x%x\n", i, data); } return (err < 0) ? err : 0; } diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index 7fe3587..a25b887 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -211,49 +211,49 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = { /* If NULL, only single value to write, stored in len */ struct stv_init { - const u8 *data; - u16 start; - u8 len; -}; - -static const u8 x1500[] = { /* 0x1500 - 0x150f */ - 0x0b, 0xa7, 0xb7, 0x00, 0x00 -}; - -static const u8 x1536[] = { /* 0x1536 - 0x153b */ - 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 + u16 addr; + u8 data; }; static const struct stv_init stv_bridge_init[] = { /* This reg is written twice. Some kind of reset? */ - {NULL, 0x1620, 0x80}, - {NULL, 0x1620, 0x00}, - {NULL, 0x1443, 0x00}, - {NULL, 0x1423, 0x04}, - {x1500, 0x1500, ARRAY_SIZE(x1500)}, - {x1536, 0x1536, ARRAY_SIZE(x1536)}, + {STV_RESET, 0x80}, + {STV_RESET, 0x00}, + {STV_SCAN_RATE, 0x00}, + {STV_I2C_FLUSH, 0x04}, + {STV_REG00, 0x0b}, + {STV_REG01, 0xa7}, + {STV_REG02, 0xb7}, + {STV_REG03, 0x00}, + {STV_REG04, 0x00}, + {0x1536, 0x02}, + {0x1537, 0x00}, + {0x1538, 0x60}, + {0x1539, 0x01}, + {0x153a, 0x20}, + {0x153b, 0x01}, }; static const u8 vv6410_sensor_init[][2] = { /* Setup registers */ - {VV6410_SETUP0, VV6410_SOFT_RESET}, - {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, + {VV6410_SETUP0, VV6410_SOFT_RESET}, + {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, /* Use shuffled read-out mode */ - {VV6410_SETUP1, BIT(6)}, - /* All modes to 1 */ - {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, - {VV6410_PINMAPPING, 0x00}, + {VV6410_SETUP1, BIT(6)}, + /* All modes to 1, FST, Fast QCK, Free running QCK, Free running LST, FST will qualify visible pixels */ + {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, + {VV6410_PINMAPPING, 0x00}, /* Pre-clock generator divide off */ - {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, + {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, - {VV6410_CLKDIV, VV6410_CLK_DIV_2}, + {VV6410_CLKDIV, VV6410_CLK_DIV_2}, /* System registers */ /* Enable voltage doubler */ - {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, - {VV6410_AT0, 0x00}, + {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, + {VV6410_AT0, 0x00}, /* Power up audio, differential */ - {VV6410_AT1, BIT(4)|BIT(0)}, + {VV6410_AT1, BIT(4) | BIT(0)}, }; #endif diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index b089c0d..c890977 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sunplus" #include "gspca.h" @@ -247,7 +249,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = { {0x30, 0x0004, 0x000a}, {0xb0, 0x0001, 0x0000}, - {0xa1, 0x0080, 0x0001}, {0x30, 0x0049, 0x0000}, {0x30, 0x0060, 0x0005}, @@ -256,8 +257,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = { {0x00, 0x0000, 0x2000}, {0x00, 0x0013, 0x2301}, {0x00, 0x0003, 0x2000}, - {0x00, 0x0000, 0x2000}, - }; /* clicksmart 420 open data ? */ @@ -328,7 +327,7 @@ static void reg_r(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -343,7 +342,7 @@ static void reg_r(struct gspca_dev *gspca_dev, len ? gspca_dev->usb_buf : NULL, len, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -368,7 +367,7 @@ static void reg_w_1(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w_1 err %d", ret); + pr_err("reg_w_1 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -388,7 +387,7 @@ static void reg_w_riv(struct gspca_dev *gspca_dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w_riv err %d", ret); + pr_err("reg_w_riv err %d\n", ret); gspca_dev->usb_err = ret; return; } diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index 7e762d5..90f0877 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -26,6 +26,8 @@ * Costantino Leandro */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "t613" #include <linux/slab.h> @@ -572,7 +574,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, tmpbuf = kmemdup(buffer, len, GFP_KERNEL); if (!tmpbuf) { - err("Out of memory"); + pr_err("Out of memory\n"); return; } usb_control_msg(gspca_dev->dev, @@ -598,7 +600,7 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev, } else { p = tmpbuf = kmalloc(len * 2, GFP_KERNEL); if (!tmpbuf) { - err("Out of memory"); + pr_err("Out of memory\n"); return; } } @@ -652,7 +654,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev) } byte = reg_r(gspca_dev, 0x0063); if (byte != 0x17) { - err("Bad sensor reset %02x", byte); + pr_err("Bad sensor reset %02x\n", byte); /* continue? */ } @@ -890,7 +892,7 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_OM6802; break; default: - err("unknown sensor %04x", sensor_id); + pr_err("unknown sensor %04x\n", sensor_id); return -EINVAL; } @@ -905,7 +907,7 @@ static int sd_init(struct gspca_dev *gspca_dev) break; /* OK */ } if (i < 0) { - err("Bad sensor reset %02x", test_byte); + pr_err("Bad sensor reset %02x\n", test_byte); return -EIO; } reg_w_buf(gspca_dev, n2, sizeof n2); @@ -1387,7 +1389,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, return 0; case V4L2_CID_EFFECTS: if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { - strncpy((char *) menu->name, + strlcpy((char *) menu->name, effects_control[menu->index], sizeof menu->name); return 0; diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 6caed73..7ee2c82 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "vc032x" #include "gspca.h" @@ -3169,7 +3171,7 @@ static void reg_r_i(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -3210,7 +3212,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -3235,8 +3237,7 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev, reg_r(gspca_dev, 0xa1, 0xb33f, 1); if (!(gspca_dev->usb_buf[0] & 0x02)) { - err("I2c Bus Busy Wait %02x", - gspca_dev->usb_buf[0]); + pr_err("I2c Bus Busy Wait %02x\n", gspca_dev->usb_buf[0]); return 0; } reg_w(gspca_dev, 0xa0, address, 0xb33a); @@ -3349,7 +3350,7 @@ static void i2c_write(struct gspca_dev *gspca_dev, msleep(20); } while (--retry > 0); if (retry <= 0) - err("i2c_write timeout"); + pr_err("i2c_write timeout\n"); } static void put_tab_to_reg(struct gspca_dev *gspca_dev, @@ -3446,7 +3447,7 @@ static int sd_init(struct gspca_dev *gspca_dev) switch (sensor) { case -1: - err("Unknown sensor..."); + pr_err("Unknown sensor...\n"); return -EINVAL; case SENSOR_HV7131R: PDEBUG(D_PROBE, "Find Sensor HV7131R"); diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c index 84dfbab..81dd4c9 100644 --- a/drivers/media/video/gspca/vicam.c +++ b/drivers/media/video/gspca/vicam.c @@ -26,6 +26,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "vicam" #define HEADER_SIZE 64 @@ -117,7 +119,7 @@ static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, data, len, 1000); if (ret < 0) - err("control msg req %02X error %d", request, ret); + pr_err("control msg req %02X error %d\n", request, ret); return ret; } @@ -189,8 +191,8 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) data, size, &act_len, 10000); /* successful, it returns 0, otherwise negative */ if (ret < 0 || act_len != size) { - err("bulk read fail (%d) len %d/%d", - ret, act_len, size); + pr_err("bulk read fail (%d) len %d/%d\n", + ret, act_len, size); return -EIO; } return 0; @@ -216,7 +218,7 @@ static void vicam_dostream(struct work_struct *work) HEADER_SIZE; buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA); if (!buffer) { - err("Couldn't allocate USB buffer"); + pr_err("Couldn't allocate USB buffer\n"); goto exit; } @@ -269,7 +271,7 @@ static int sd_init(struct gspca_dev *gspca_dev) ret = request_ihex_firmware(&fw, "vicam/firmware.fw", &gspca_dev->dev->dev); if (ret) { - err("Failed to load \"vicam/firmware.fw\": %d\n", ret); + pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret); return ret; } diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c index 4a9e622..27d2cef 100644 --- a/drivers/media/video/gspca/w996Xcf.c +++ b/drivers/media/video/gspca/w996Xcf.c @@ -31,6 +31,8 @@ the sensor drivers to v4l2 sub drivers, and properly split of this driver from ov519.c */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ #define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET]) @@ -81,7 +83,7 @@ static void w9968cf_write_fsb(struct sd *sd, u16* data) USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, value, 0x06, sd->gspca_dev.usb_buf, 6, 500); if (ret < 0) { - err("Write FSB registers failed (%d)", ret); + pr_err("Write FSB registers failed (%d)\n", ret); sd->gspca_dev.usb_err = ret; } } @@ -108,7 +110,7 @@ static void w9968cf_write_sb(struct sd *sd, u16 value) udelay(W9968CF_I2C_BUS_DELAY); if (ret < 0) { - err("Write SB reg [01] %04x failed", value); + pr_err("Write SB reg [01] %04x failed\n", value); sd->gspca_dev.usb_err = ret; } } @@ -135,7 +137,7 @@ static int w9968cf_read_sb(struct sd *sd) ret = sd->gspca_dev.usb_buf[0] | (sd->gspca_dev.usb_buf[1] << 8); } else { - err("Read SB reg [01] failed"); + pr_err("Read SB reg [01] failed\n"); sd->gspca_dev.usb_err = ret; } diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c index c089a0f..3aed42a 100644 --- a/drivers/media/video/gspca/xirlink_cit.c +++ b/drivers/media/video/gspca/xirlink_cit.c @@ -27,6 +27,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "xirlink-cit" #include <linux/input.h> @@ -800,8 +802,8 @@ static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, value, index, NULL, 0, 1000); if (err < 0) - err("Failed to write a register (index 0x%04X," - " value 0x%02X, error %d)", index, value, err); + pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n", + index, value, err); return 0; } @@ -816,8 +818,8 @@ static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index, int verbose) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x00, index, buf, 8, 1000); if (res < 0) { - err("Failed to read a register (index 0x%04X, error %d)", - index, res); + pr_err("Failed to read a register (index 0x%04X, error %d)\n", + index, res); return res; } @@ -1587,7 +1589,7 @@ static int cit_get_packet_size(struct gspca_dev *gspca_dev) intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); alt = usb_altnum_to_altsetting(intf, gspca_dev->alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); return -EIO; } @@ -2824,7 +2826,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); if (ret < 0) - err("set alt 1 err %d", ret); + pr_err("set alt 1 err %d\n", ret); return ret; } diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 61cdd56..30ea1e4 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "zc3xx" #include <linux/input.h> @@ -5666,7 +5668,7 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_r_i err %d", ret); + pr_err("reg_r_i err %d\n", ret); gspca_dev->usb_err = ret; return 0; } @@ -5698,7 +5700,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w_i err %d", ret); + pr_err("reg_w_i err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -5724,7 +5726,7 @@ static u16 i2c_read(struct gspca_dev *gspca_dev, msleep(20); retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ if (retbyte != 0x00) - err("i2c_r status error %02x", retbyte); + pr_err("i2c_r status error %02x\n", retbyte); retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", @@ -5748,7 +5750,7 @@ static u8 i2c_write(struct gspca_dev *gspca_dev, msleep(1); retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ if (retbyte != 0x00) - err("i2c_w status error %02x", retbyte); + pr_err("i2c_w status error %02x\n", retbyte); PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", reg, valH, valL, retbyte); return retbyte; @@ -6497,7 +6499,7 @@ static int sd_init(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor GC0303"); break; default: - warn("Unknown sensor - set to TAS5130C"); + pr_warn("Unknown sensor - set to TAS5130C\n"); sd->sensor = SENSOR_TAS5130C; } break; @@ -6603,7 +6605,7 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_OV7620; /* same sensor (?) */ break; default: - err("Unknown sensor %04x", sensor); + pr_err("Unknown sensor %04x\n", sensor); return -EINVAL; } } @@ -6970,6 +6972,7 @@ static const struct sd_desc sd_desc = { }; static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x03f0, 0x1b07)}, {USB_DEVICE(0x041e, 0x041e)}, {USB_DEVICE(0x041e, 0x4017)}, {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile index 3baa9f6..52f057f 100644 --- a/drivers/media/video/hdpvr/Makefile +++ b/drivers/media/video/hdpvr/Makefile @@ -2,6 +2,6 @@ hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o -EXTRA_CFLAGS += -Idrivers/media/video +ccflags-y += -Idrivers/media/video -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index a27d93b..060353e 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c @@ -17,7 +17,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/uaccess.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <linux/usb.h> #include <linux/mutex.h> #include <linux/i2c.h> @@ -297,6 +297,11 @@ static int hdpvr_probe(struct usb_interface *interface, dev->workqueue = 0; + /* init video transfer queues first of all */ + /* to prevent oops in hdpvr_delete() on error paths */ + INIT_LIST_HEAD(&dev->free_buff_list); + INIT_LIST_HEAD(&dev->rec_buff_list); + /* register v4l2_device early so it can be used for printks */ if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) { err("v4l2_device_register failed"); @@ -319,10 +324,6 @@ static int hdpvr_probe(struct usb_interface *interface, if (!dev->workqueue) goto error; - /* init video transfer queues */ - INIT_LIST_HEAD(&dev->free_buff_list); - INIT_LIST_HEAD(&dev->rec_buff_list); - dev->options = hdpvr_default_options; if (default_video_input < HDPVR_VIDEO_INPUTS) @@ -373,12 +374,6 @@ static int hdpvr_probe(struct usb_interface *interface, } mutex_unlock(&dev->io_mutex); - if (hdpvr_register_videodev(dev, &interface->dev, - video_nr[atomic_inc_return(&dev_nr)])) { - v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); - goto error; - } - #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) retval = hdpvr_register_i2c_adapter(dev); if (retval < 0) { @@ -399,6 +394,13 @@ static int hdpvr_probe(struct usb_interface *interface, } #endif + retval = hdpvr_register_videodev(dev, &interface->dev, + video_nr[atomic_inc_return(&dev_nr)]); + if (retval < 0) { + v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); + goto reg_fail; + } + /* let the user know what node this device is now attached to */ v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", video_device_node_name(dev->video_dev)); @@ -474,5 +476,6 @@ module_init(hdpvr_init); module_exit(hdpvr_exit); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2.1"); MODULE_AUTHOR("Janne Grunau"); MODULE_DESCRIPTION("Hauppauge HD PVR driver"); diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index 2a1ac28..82e819f 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -17,6 +17,7 @@ #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/export.h> #include "hdpvr.h" diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index 4c0394a..41fd57b 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -17,7 +17,6 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/mutex.h> -#include <linux/version.h> #include <linux/workqueue.h> #include <linux/videodev2.h> @@ -575,7 +574,6 @@ static int vidioc_querycap(struct file *file, void *priv, strcpy(cap->driver, "hdpvr"); strcpy(cap->card, "Hauppauge HD PVR"); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = HDPVR_VERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE; diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h index 072f23c..d6439db 100644 --- a/drivers/media/video/hdpvr/hdpvr.h +++ b/drivers/media/video/hdpvr/hdpvr.h @@ -18,12 +18,6 @@ #include <media/v4l2-device.h> #include <media/ir-kbd-i2c.h> -#define HDPVR_MAJOR_VERSION 0 -#define HDPVR_MINOR_VERSION 2 -#define HDPVR_RELEASE 0 -#define HDPVR_VERSION \ - KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE) - #define HDPVR_MAX 8 #define HDPVR_I2C_MAX_SIZE 128 diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 26ce0d6..71ab76a 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -7,8 +7,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 0fb7552..41108a9 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1180,6 +1180,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev, setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + if (itv->options.radio > 0) + setup.mode_mask |= T_RADIO; setup.tuner_callback = (setup.type == TUNER_XC2028) ? ivtv_reset_tuner_gpio : NULL; ivtv_call_all(itv, tuner, s_type_addr, &setup); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 84bdf0f..8f9cc17 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -36,7 +36,6 @@ * using information provided by Jiun-Kuei Jung @ AVerMedia. */ -#include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index a7f54b0..38f0522 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -722,8 +722,8 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) /* If there are subscribed events, then only use the new event API instead of the old video.h based API. */ - if (!list_empty(&id->fh.events->subscribed)) { - poll_wait(filp, &id->fh.events->wait, wait); + if (!list_empty(&id->fh.subscribed)) { + poll_wait(filp, &id->fh.wait, wait); /* Turn off the old-style vsync events */ clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); if (v4l2_event_pending(&id->fh)) @@ -750,6 +750,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + unsigned res = 0; /* Start a capture if there is none */ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { @@ -769,12 +770,16 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) /* add stream's waitq to the poll list */ IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); + if (v4l2_event_pending(&id->fh)) + res |= POLLPRI; + else + poll_wait(filp, &id->fh.wait, wait); if (s->q_full.length || s->q_io.length) - return POLLIN | POLLRDNORM; + return res | POLLIN | POLLRDNORM; if (eof) - return POLLHUP; - return 0; + return res | POLLHUP; + return res; } void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) @@ -961,10 +966,6 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) return -ENOMEM; } v4l2_fh_init(&item->fh, s->vdev); - if (s->type == IVTV_DEC_STREAM_TYPE_YUV || - s->type == IVTV_DEC_STREAM_TYPE_MPG) { - res = v4l2_event_alloc(&item->fh, 60); - } if (res < 0) { v4l2_fh_exit(&item->fh); kfree(item); diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 120c7d8..ecafa69 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -757,7 +757,6 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); - vcap->version = IVTV_DRIVER_VERSION; /* version */ vcap->capabilities = itv->v4l2_cap; /* capabilities */ return 0; } @@ -1204,9 +1203,7 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced cap->service_lines[f][l] = set; } } - return 0; - } - if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { + } else if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) return -EINVAL; if (itv->is_60hz) { @@ -1216,9 +1213,16 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced cap->service_lines[0][23] = V4L2_SLICED_WSS_625; cap->service_lines[0][16] = V4L2_SLICED_VPS; } - return 0; + } else { + return -EINVAL; } - return -EINVAL; + + set = 0; + for (f = 0; f < 2; f++) + for (l = 0; l < 24; l++) + set |= cap->service_lines[f][l]; + cap->service_set = set; + return 0; } static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) @@ -1451,11 +1455,11 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti switch (sub->type) { case V4L2_EVENT_VSYNC: case V4L2_EVENT_EOS: - break; + case V4L2_EVENT_CTRL: + return v4l2_event_subscribe(fh, sub, 0); default: return -EINVAL; } - return v4l2_event_subscribe(fh, sub); } static int ivtv_log_status(struct file *file, void *fh) diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index b67a404..a20f346 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -21,11 +21,6 @@ #define IVTV_VERSION_H #define IVTV_DRIVER_NAME "ivtv" -#define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 4 -#define IVTV_DRIVER_VERSION_PATCHLEVEL 2 - -#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) -#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) +#define IVTV_VERSION "1.4.3" #endif diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig index ddb3314..302dc3d 100644 --- a/drivers/media/video/m5mols/Kconfig +++ b/drivers/media/video/m5mols/Kconfig @@ -1,6 +1,5 @@ config VIDEO_M5MOLS tristate "Fujitsu M-5MOLS 8MP sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API &&\ - (VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS_MIPI_CSIS) + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ---help--- This driver supports Fujitsu M-5MOLS camera sensor with ISP diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/video/m5mols/Makefile index b5d19bf..0a44e02 100644 --- a/drivers/media/video/m5mols/Makefile +++ b/drivers/media/video/m5mols/Makefile @@ -1,3 +1,3 @@ -m5mols-objs := m5mols_core.o m5mols_controls.o +m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index 94022e2..82c8817 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h @@ -1,5 +1,5 @@ /* - * Header for M5MOLS 8M Pixel camera sensor with ISP + * Header for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. * Author: HeungJun Kim <riverful.kim@samsung.com> @@ -19,24 +19,12 @@ #include <media/v4l2-subdev.h> #include "m5mols_reg.h" -#define M5MO_JPEG_MAXSIZE 0x3A0000 -#define M5MO_THUMB_MAXSIZE 0xFC00 -#define M5MO_POST_MAXSIZE 0xBB800 -#define M5MO_JPEG_MEMSIZE M5MO_JPEG_MAXSIZE + M5MO_THUMB_MAXSIZE + M5MO_POST_MAXSIZE - -#define v4l2msg(fmt, arg...) do { \ - v4l2_dbg(1, m5mols_debug, &info->sd, fmt, ## arg); \ -} while (0) - extern int m5mols_debug; -enum m5mols_mode { - MODE_SYSINIT, - MODE_PARMSET, - MODE_MONITOR, - MODE_CAPTURE, - MODE_UNKNOWN, -}; +#define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd) + +#define to_sd(__ctrl) \ + (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd) enum m5mols_restype { M5MOLS_RESTYPE_MONITOR, @@ -44,341 +32,264 @@ enum m5mols_restype { M5MOLS_RESTYPE_MAX, }; -enum m5mols_status { - STATUS_SYSINIT, - STATUS_PARMSET, - STATUS_MONITOR, - STATUS_AUTO_FOCUS, - STATUS_FACE_DETECTION, - STATUS_DUAL_CAPTURE, - STATUS_SINGLE_CAPTURE, - STATUS_PREVIEW, - STATUS_UNKNOWN, -}; - -enum m5mols_intterrupt_bit { - INT_BIT_MODE, - INT_BIT_AF, - INT_BIT_ZOOM, - INT_BIT_CAPTURE, - INT_BIT_FRAME_SYNC, - INT_BIT_FD, - INT_BIT_LENS_INIT, - INT_BIT_SOUND, -}; - -enum m5mols_i2c_size { - I2C_8BIT = 1, - I2C_16BIT = 2, - I2C_32BIT = 4, - I2C_MAX = 4, -}; - -enum m5mols_fps { - M5MOLS_FPS_AUTO = 0, - M5MOLS_FPS_10 = 10, - M5MOLS_FPS_12 = 12, - M5MOLS_FPS_15 = 15, - M5MOLS_FPS_20 = 20, - M5MOLS_FPS_21 = 21, - M5MOLS_FPS_22 = 22, - M5MOLS_FPS_23 = 23, - M5MOLS_FPS_24 = 24, - M5MOLS_FPS_30 = 30, - M5MOLS_FPS_MAX = M5MOLS_FPS_30, -}; - -enum m5mols_res_type { - M5MOLS_RES_MON, - /* It's not supported below yet. */ - M5MOLS_RES_CAPTURE, - M5MOLS_RES_MAX, -}; - +/** + * struct m5mols_resolution - structure for the resolution + * @type: resolution type according to the pixel code + * @width: width of the resolution + * @height: height of the resolution + * @reg: resolution preset register value + */ struct m5mols_resolution { - u8 value; - enum m5mols_res_type type; - u16 width; - u16 height; -}; - -struct m5mols_format { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; -}; - -struct m5mols_control { - u32 id; - s32 min; - s32 max; - u32 step; - s32 def; + u8 reg; + enum m5mols_restype type; + u16 width; + u16 height; }; +/** + * struct m5mols_exif - structure for the EXIF information of M-5MOLS + * @exposure_time: exposure time register value + * @shutter_speed: speed of the shutter register value + * @aperture: aperture register value + * @exposure_bias: it calls also EV bias + * @iso_speed: ISO register value + * @flash: status register value of the flash + * @sdr: status register value of the Subject Distance Range + * @qval: not written exact meaning in document + */ struct m5mols_exif { - u32 exposure_time; - u32 shutter_speed; - u32 aperture; - u32 brightness; - u32 exposure_bias; - u16 iso_speed; - u16 flash; - u16 sdr; /* subject(object) distance range */ - u16 qval; /* This is not written precisely in datasheet. */ + u32 exposure_time; + u32 shutter_speed; + u32 aperture; + u32 brightness; + u32 exposure_bias; + u16 iso_speed; + u16 flash; + u16 sdr; + u16 qval; }; +/** + * struct m5mols_capture - Structure for the capture capability + * @exif: EXIF information + * @main: size in bytes of the main image + * @thumb: size in bytes of the thumb image, if it was accompanied + * @total: total size in bytes of the produced image + */ struct m5mols_capture { - struct m5mols_exif exif; - u32 main; - u32 thumb; - u32 total; + struct m5mols_exif exif; + u32 main; + u32 thumb; + u32 total; +}; + +/** + * struct m5mols_scenemode - structure for the scenemode capability + * @metering: metering light register value + * @ev_bias: EV bias register value + * @wb_mode: mode which means the WhiteBalance is Auto or Manual + * @wb_preset: whitebalance preset register value in the Manual mode + * @chroma_en: register value whether the Chroma capability is enabled or not + * @chroma_lvl: chroma's level register value + * @edge_en: register value Whether the Edge capability is enabled or not + * @edge_lvl: edge's level register value + * @af_range: Auto Focus's range + * @fd_mode: Face Detection mode + * @mcc: Multi-axis Color Conversion which means emotion color + * @light: status of the Light + * @flash: status of the Flash + * @tone: Tone color which means Contrast + * @iso: ISO register value + * @capt_mode: Mode of the Image Stabilization while the camera capturing + * @wdr: Wide Dynamic Range register value + * + * The each value according to each scenemode is recommended in the documents. + */ +struct m5mols_scenemode { + u8 metering; + u8 ev_bias; + u8 wb_mode; + u8 wb_preset; + u8 chroma_en; + u8 chroma_lvl; + u8 edge_en; + u8 edge_lvl; + u8 af_range; + u8 fd_mode; + u8 mcc; + u8 light; + u8 flash; + u8 tone; + u8 iso; + u8 capt_mode; + u8 wdr; }; +/** + * struct m5mols_version - firmware version information + * @customer: customer information + * @project: version of project information according to customer + * @fw: firmware revision + * @hw: hardware revision + * @param: version of the parameter + * @awb: Auto WhiteBalance algorithm version + * @str: information about manufacturer and packaging vendor + * @af: Auto Focus version + * + * The register offset starts the customer version at 0x0, and it ends + * the awb version at 0x09. The customer, project information occupies 1 bytes + * each. And also the fw, hw, param, awb each requires 2 bytes. The str is + * unique string associated with firmware's version. It includes information + * about manufacturer and the vendor of the sensor's packaging. The least + * significant 2 bytes of the string indicate packaging manufacturer. + */ +#define VERSION_STRING_SIZE 22 struct m5mols_version { - u8 ctm_code; /* customer code */ - u8 pj_code; /* project code */ - u16 fw; /* firmware version */ - u16 hw; /* hardware version */ - u16 parm; /* parameter version */ - u16 awb; /* AWB version */ + u8 customer; + u8 project; + u16 fw; + u16 hw; + u16 param; + u16 awb; + u8 str[VERSION_STRING_SIZE]; + u8 af; }; +/** + * struct m5mols_info - M-5MOLS driver data structure + * @pdata: platform data + * @sd: v4l-subdev instance + * @pad: media pad + * @ffmt: current fmt according to resolution type + * @res_type: current resolution type + * @irq_waitq: waitqueue for the capture + * @work_irq: workqueue for the IRQ + * @flags: state variable for the interrupt handler + * @handle: control handler + * @autoexposure: Auto Exposure control + * @exposure: Exposure control + * @autowb: Auto White Balance control + * @colorfx: Color effect control + * @saturation: Saturation control + * @zoom: Zoom control + * @ver: information of the version + * @cap: the capture mode attributes + * @power: current sensor's power status + * @ctrl_sync: true means all controls of the sensor are initialized + * @int_capture: true means the capture interrupt is issued once + * @lock_ae: true means the Auto Exposure is locked + * @lock_awb: true means the Aut WhiteBalance is locked + * @resolution: register value for current resolution + * @interrupt: register value for current interrupt status + * @mode: register value for current operation mode + * @mode_save: register value for current operation mode for saving + * @set_power: optional power callback to the board code + */ struct m5mols_info { - struct v4l2_subdev sd; + const struct m5mols_platform_data *pdata; + struct v4l2_subdev sd; struct media_pad pad; + struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; int res_type; - u8 resolution; - struct v4l2_mbus_framefmt fmt[M5MOLS_RES_MAX]; - struct v4l2_fract tpf; + wait_queue_head_t irq_waitq; + struct work_struct work_irq; + unsigned long flags; - struct v4l2_ctrl_handler handle; + struct v4l2_ctrl_handler handle; + /* Autoexposure/exposure control cluster */ struct { - /* support only AE of the Monitor Mode in this version */ - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - bool is_ae_lock; + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; }; - struct v4l2_ctrl *autofocus; - bool is_focus; - struct v4l2_ctrl *autowb; - bool is_awb_lock; - struct v4l2_ctrl *colorfx; - struct v4l2_ctrl *saturation; - struct v4l2_ctrl *zoom; - struct v4l2_ctrl *jpeg_size; - struct v4l2_ctrl *encoded_size; - - enum m5mols_mode mode; - enum m5mols_mode mode_backup; - enum m5mols_status status; - enum v4l2_mbus_pixelcode code; - - struct m5mols_capture cap; - wait_queue_head_t cap_wait; - bool captured; - - const struct m5mols_platform_data *pdata; - struct m5mols_version ver; - struct work_struct work; - bool power; - - /* for additional power if needed. */ + struct v4l2_ctrl *autowb; + struct v4l2_ctrl *colorfx; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *zoom; + + struct m5mols_version ver; + struct m5mols_capture cap; + bool power; + bool ctrl_sync; + bool lock_ae; + bool lock_awb; + u8 resolution; + u8 interrupt; + u8 mode; + u8 mode_save; int (*set_power)(struct device *dev, int on); }; -/* control functions */ -int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); - -/* I2C functions - referenced by below I2C helper functions */ -int m5mols_read_reg(struct v4l2_subdev *sd, enum m5mols_i2c_size size, - u8 category, u8 cmd, u32 *val); -int m5mols_write_reg(struct v4l2_subdev *sd, enum m5mols_i2c_size size, - u8 category, u8 cmd, u32 val); -int m5mols_check_busy(struct v4l2_subdev *sd, - u8 category, u8 cmd, u32 value); -int m5mols_set_mode(struct v4l2_subdev *sd, enum m5mols_mode mode); -enum m5mols_status m5mols_get_status(struct v4l2_subdev *sd); +#define ST_CAPT_IRQ 0 +#define is_powered(__info) (__info->power) +#define is_ctrl_synced(__info) (__info->ctrl_sync) +#define is_available_af(__info) (__info->ver.af) +#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) +#define is_manufacturer(__info, __manufacturer) \ + (__info->ver.str[0] == __manufacturer[0] && \ + __info->ver.str[1] == __manufacturer[1]) /* - * helper functions + * I2C operation of the M-5MOLS + * + * The I2C read operation of the M-5MOLS requires 2 messages. The first + * message sends the information about the command, command category, and total + * message size. The second message is used to retrieve the data specifed in + * the first message + * + * 1st message 2nd message + * +-------+---+----------+-----+-------+ +------+------+------+------+ + * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] | + * +-------+---+----------+-----+-------+ +------+------+------+------+ + * - size1: message data size(5 in this case) + * - size2: desired buffer size of the 2nd message + * - d[0..3]: according to size2 + * + * The I2C write operation needs just one message. The message includes + * category, command, total size, and desired data. + * + * 1st message + * +-------+---+----------+-----+------+------+------+------+ + * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] | + * +-------+---+----------+-----+------+------+------+------+ + * - d[0..3]: according to size1 */ -static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *sd) -{ - return container_of(sd, struct m5mols_info, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct m5mols_info, handle)->sd; -} - -static inline bool is_streaming(struct v4l2_subdev *sd) -{ - struct m5mols_info *info = to_m5mols(sd); - return (info->mode == MODE_MONITOR) || (info->mode == MODE_CAPTURE); -} - -static inline bool is_stoped(struct v4l2_subdev *sd) -{ - struct m5mols_info *info = to_m5mols(sd); - return (info->mode != MODE_MONITOR) && (info->mode != MODE_CAPTURE); -} - -static inline bool is_powerup(struct v4l2_subdev *sd) -{ - struct m5mols_info *info = to_m5mols(sd); - return info->power; -} - -static inline int m5mols_set_mode_backup(struct v4l2_subdev *sd, - enum m5mols_mode mode) -{ - struct m5mols_info *info = to_m5mols(sd); - - info->mode_backup = info->mode; - return m5mols_set_mode(sd, mode); -} - -static inline int m5mols_set_mode_restore(struct v4l2_subdev *sd) -{ - struct m5mols_info *info = to_m5mols(sd); - int ret; - - ret = m5mols_set_mode(sd, info->mode_backup); - if (!ret) - info->mode = info->mode_backup; - return ret; -} - -static inline int __must_check i2c_w8_system(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_SYSTEM, cmd, val); -} - -static inline int __must_check i2c_w8_param(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_PARAM, cmd, val); -} - -static inline int __must_check i2c_w8_mon(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_MON, cmd, val); -} - -static inline int __must_check i2c_w8_ae(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_AE, cmd, val); -} - -static inline int __must_check i2c_w16_ae(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_16BIT, CAT_AE, cmd, val); -} - -static inline int __must_check i2c_w8_wb(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_WB, cmd, val); -} - -static inline int __must_check i2c_w8_lens(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_LENS, cmd, val); -} - -static inline int __must_check i2c_w8_capt_parm(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_CAPTURE_PARAMETER, cmd, val); -} - -static inline int __must_check i2c_w8_capt_ctrl(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_CAPTURE_CONTROL, cmd, val); -} +int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); +int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); +int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); +int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); -static inline int __must_check i2c_w8_flash(struct v4l2_subdev *sd, - u8 cmd, u32 val) -{ - return m5mols_write_reg(sd, I2C_8BIT, CAT_FLASH, cmd, val); -} - -static inline int __must_check i2c_r8_system(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_8BIT, CAT_SYSTEM, cmd, val); -} - -static inline int __must_check i2c_r8_param(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_8BIT, CAT_PARAM, cmd, val); -} - -static inline int __must_check i2c_r8_mon(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_8BIT, CAT_MON, cmd, val); -} - -static inline int __must_check i2c_r8_ae(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_8BIT, CAT_AE, cmd, val); -} - -static inline int __must_check i2c_r16_ae(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_16BIT, CAT_AE, cmd, val); -} - -static inline int __must_check i2c_r8_lens(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_8BIT, CAT_LENS, cmd, val); -} - -static inline int __must_check i2c_r32_capt_ctrl(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_32BIT, CAT_CAPTURE_CONTROL, cmd, val); -} - -static inline int __must_check i2c_r16_exif(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_16BIT, CAT_EXIF, cmd, val); -} - -static inline int __must_check i2c_r32_exif(struct v4l2_subdev *sd, - u8 cmd, u32 *val) -{ - return m5mols_read_reg(sd, I2C_32BIT, CAT_EXIF, cmd, val); -} - -static int m5mols_set_ae_lock(struct m5mols_info *info, bool lock) -{ - struct v4l2_subdev *sd = &info->sd; - - info->is_ae_lock = lock; - - return i2c_w8_ae(sd, CAT3_AE_LOCK, !!lock); -} +/* + * Mode operation of the M-5MOLS + * + * Changing the mode of the M-5MOLS is needed right executing order. + * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed + * by user. There are various categories associated with each mode. + * + * +============================================================+ + * | mode | category | + * +============================================================+ + * | FLASH | FLASH(only after Stand-by or Power-on) | + * | SYSTEM | SYSTEM(only after sensor arm-booting) | + * | PARAMETER | PARAMETER | + * | MONITOR | MONITOR(preview), Auto Focus, Face Detection | + * | CAPTURE | Single CAPTURE, Preview(recording) | + * +============================================================+ + * + * The available executing order between each modes are as follows: + * PARAMETER <---> MONITOR <---> CAPTURE + */ +int m5mols_mode(struct m5mols_info *info, u8 mode); -static int m5mols_set_awb_lock(struct m5mols_info *info, bool lock) -{ - struct v4l2_subdev *sd = &info->sd; +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); +int m5mols_sync_controls(struct m5mols_info *info); +int m5mols_start_capture(struct m5mols_info *info); +int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); +int m5mols_lock_3a(struct m5mols_info *info, bool lock); +int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); - info->is_awb_lock = lock; +/* The firmware function */ +int m5mols_update_fw(struct v4l2_subdev *sd, + int (*set_power)(struct m5mols_info *, bool)); - return i2c_w8_wb(sd, CAT6_AWB_LOCK, !!lock); -} #endif /* M5MOLS_H */ diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index d947192..3248ac8 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c @@ -18,11 +18,9 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/version.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/videodev2.h> -#include <linux/version.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c index 3e08018..d135d20 100644 --- a/drivers/media/video/m5mols/m5mols_controls.c +++ b/drivers/media/video/m5mols/m5mols_controls.c @@ -1,5 +1,5 @@ /* - * Controls for M5MOLS 8M Pixel camera sensor with ISP + * Controls for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. * Author: HeungJun Kim <riverful.kim@samsung.com> @@ -14,186 +14,285 @@ */ #include <linux/i2c.h> +#include <linux/delay.h> #include <linux/videodev2.h> #include <media/v4l2-ctrls.h> #include "m5mols.h" #include "m5mols_reg.h" -static int m5mols_wb_mode(struct m5mols_info *info, struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = &info->sd; - int ret; - - if (info->is_awb_lock) { - ret = m5mols_set_awb_lock(info, false); - if (!ret) - return ret; - } - - /* 0x01 : Auto Whitebalance, 0x02 : Manual Whitebalance. */ - return i2c_w8_wb(sd, CAT6_AWB_MODE, (ctrl->val) ? 0x1 : 0x2); +static struct m5mols_scenemode m5mols_default_scenemode[] = { + [REG_SCENE_NORMAL] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF, + 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_PORTRAIT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 4, + REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_LANDSCAPE] = { + REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 4, REG_EDGE_ON, 6, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_SPORTS] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_PARTY_INDOOR] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 4, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_BEACH_SNOW] = { + REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 4, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_SUNSET] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, + REG_AWB_DAYLIGHT, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_DAWN_DUSK] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, + REG_AWB_FLUORESCENT_1, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_FALL] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 5, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_NIGHT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_AGAINST_LIGHT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_FIRE] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_TEXT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 7, + REG_AF_MACRO, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON, + }, + [REG_SCENE_CANDLE] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, +}; -} - -static int m5mols_exposure_mode(struct m5mols_info *info, - struct v4l2_ctrl *ctrl) +/** + * m5mols_do_scenemode() - Change current scenemode + * @mode: Desired mode of the scenemode + * + * WARNING: The execution order is important. Do not change the order. + */ +int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) { struct v4l2_subdev *sd = &info->sd; + struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; int ret; - if (info->is_ae_lock) { - ret = m5mols_set_ae_lock(info, false); - if (ret) - return ret; - } - - /* 0x01 : Auto Exposure, 0x0 : Manual Exposure. */ - return i2c_w8_ae(sd, CAT3_AE_MODE, - (ctrl->val == V4L2_EXPOSURE_AUTO) ? 0x1 : 0x0); -} - -static int m5mols_exposure(struct m5mols_info *info) -{ - struct v4l2_subdev *sd = &info->sd; - - return i2c_w16_ae(sd, CAT3_MANUAL_GAIN_MON, info->exposure->val); -} - -static int m5mols_zoom(struct m5mols_info *info, struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = &info->sd; - - return i2c_w8_mon(sd, CAT2_ZOOM, ctrl->val); -} - -static int m5mols_focus_mode(struct m5mols_info *info, - struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = &info->sd; - u32 reg; - int ret; + if (mode > REG_SCENE_CANDLE) + return -EINVAL; - ret = m5mols_set_mode(sd, MODE_MONITOR); + ret = m5mols_lock_3a(info, false); + if (!ret) + ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode); + if (!ret) + ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode); + if (!ret) + ret = m5mols_write(sd, AE_MODE, scenemode.metering); + if (!ret) + ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias); + if (!ret) + ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode); + if (!ret) + ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset); + if (!ret) + ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en); + if (!ret) + ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl); + if (!ret) + ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en); + if (!ret) + ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl); + if (!ret && is_available_af(info)) + ret = m5mols_write(sd, AF_MODE, scenemode.af_range); + if (!ret && is_available_af(info)) + ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode); + if (!ret) + ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone); + if (!ret) + ret = m5mols_write(sd, AE_ISO, scenemode.iso); if (!ret) - ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); + ret = m5mols_mode(info, REG_CAPTURE); if (!ret) - ret = i2c_w8_system(sd, CAT0_INT_ENABLE, (1 << INT_BIT_AF)); + ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); if (!ret) - /* must be excuted in the monitor mode */ - ret = i2c_w8_lens(sd, CATA_INIT_AF_FUNC, 0x1); + ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc); + if (!ret) + ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light); + if (!ret) + ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash); + if (!ret) + ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); + if (!ret) + ret = m5mols_mode(info, REG_MONITOR); - /* 0x0 : Normal AF mode - * 0x1 : Macro AF mode - * 0x2 : Continuous AF mode (Not working) */ - return i2c_w8_lens(sd, CATA_AF_MODE, 0x0); + return ret; } -static int m5mols_focus(struct m5mols_info *info, struct v4l2_ctrl *ctrl) +static int m5mols_lock_ae(struct m5mols_info *info, bool lock) { - struct v4l2_subdev *sd = &info->sd; + int ret = 0; - /* 0x0: Stop, - 0x1: Excute AF, - 0x02: Excutre MF rel(Not tested), - 0x03: Excute MF absol(Not tested) */ - return i2c_w8_lens(sd, CATA_AF_EXCUTE, ctrl->val); + if (info->lock_ae != lock) + ret = m5mols_write(&info->sd, AE_LOCK, + lock ? REG_AE_LOCK : REG_AE_UNLOCK); + if (!ret) + info->lock_ae = lock; + + return ret; } -static int m5mols_set_saturation(struct m5mols_info *info, - struct v4l2_ctrl *ctrl) +static int m5mols_lock_awb(struct m5mols_info *info, bool lock) { - struct v4l2_subdev *sd = &info->sd; - static u8 m5mols_chroma_lvl[] = { - 0x1c, 0x3e, 0x5f, 0x80, 0xa1, 0xc2, 0xe4, - }; - int ret; + int ret = 0; - ret = i2c_w8_mon(sd, CAT2_CHROMA_LVL, m5mols_chroma_lvl[ctrl->val]); + if (info->lock_awb != lock) + ret = m5mols_write(&info->sd, AWB_LOCK, + lock ? REG_AWB_LOCK : REG_AWB_UNLOCK); if (!ret) - ret = i2c_w8_mon(sd, CAT2_CHROMA_EN, true); + info->lock_awb = lock; return ret; } -static int m5mols_set_colorfx(struct m5mols_info *info, struct v4l2_ctrl *ctrl) +/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */ +int m5mols_lock_3a(struct m5mols_info *info, bool lock) { - struct v4l2_subdev *sd = &info->sd; - static u8 m5mols_effects_gamma[] = { /* cat 1: Effects */ - [V4L2_COLORFX_NEGATIVE] = 0x01, - [V4L2_COLORFX_EMBOSS] = 0x06, - [V4L2_COLORFX_SKETCH] = 0x07, - }; - static u8 m5mols_cfixb_chroma[] = { /* cat 2: Cr for effect */ - [V4L2_COLORFX_BW] = 0x0, - [V4L2_COLORFX_SEPIA] = 0xd8, - [V4L2_COLORFX_SKY_BLUE] = 0x40, - [V4L2_COLORFX_GRASS_GREEN] = 0xe0, - }; - static u8 m5mols_cfixr_chroma[] = { /* cat 2: Cb for effect */ - [V4L2_COLORFX_BW] = 0x0, - [V4L2_COLORFX_SEPIA] = 0x18, - [V4L2_COLORFX_SKY_BLUE] = 0x00, - [V4L2_COLORFX_GRASS_GREEN] = 0xe0, - }; - int ret = -EINVAL; - - switch (ctrl->val) { - case V4L2_COLORFX_NONE: - return i2c_w8_mon(sd, CAT2_COLOR_EFFECT, false); - case V4L2_COLORFX_BW: /* chroma: Gray */ - case V4L2_COLORFX_SEPIA: /* chroma: Sepia */ - case V4L2_COLORFX_SKY_BLUE: /* chroma: Blue */ - case V4L2_COLORFX_GRASS_GREEN: /* chroma: Green */ - ret = i2c_w8_mon(sd, CAT2_CFIXB, - m5mols_cfixb_chroma[ctrl->val]); - if (!ret) - ret = i2c_w8_mon(sd, CAT2_CFIXR, - m5mols_cfixr_chroma[ctrl->val]); - if (!ret) - ret = i2c_w8_mon(sd, CAT2_COLOR_EFFECT, true); - return ret; - case V4L2_COLORFX_NEGATIVE: /* gamma: Negative */ - case V4L2_COLORFX_EMBOSS: /* gamma: Emboss */ - case V4L2_COLORFX_SKETCH: /* gamma: Outline */ - ret = i2c_w8_param(sd, CAT1_EFFECT, - m5mols_effects_gamma[ctrl->val]); - if (!ret) - ret = i2c_w8_mon(sd, CAT2_COLOR_EFFECT, true); - return ret; - } + int ret; + + ret = m5mols_lock_ae(info, lock); + if (!ret) + ret = m5mols_lock_awb(info, lock); + /* Don't need to handle unlocking AF */ + if (!ret && is_available_af(info) && lock) + ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); return ret; } +/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */ int m5mols_set_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); struct m5mols_info *info = to_m5mols(sd); - int ret = 0; + int ret; switch (ctrl->id) { case V4L2_CID_ZOOM_ABSOLUTE: - return m5mols_zoom(info, ctrl); - case V4L2_CID_FOCUS_AUTO: - if (ctrl->val != 0) - ret = m5mols_focus_mode(info, ctrl); - if (!ret) - ret = m5mols_focus(info, ctrl); - return ret; + return m5mols_write(sd, MON_ZOOM, ctrl->val); + case V4L2_CID_EXPOSURE_AUTO: - if (!ctrl->is_new) - ctrl->val = V4L2_EXPOSURE_MANUAL; - ret = m5mols_exposure_mode(info, ctrl); - if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) - ret = m5mols_exposure(info); + ret = m5mols_lock_ae(info, + ctrl->val == V4L2_EXPOSURE_AUTO ? false : true); + if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO) + ret = m5mols_write(sd, AE_MODE, REG_AE_ALL); + if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) { + int val = info->exposure->val; + ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); + if (!ret) + ret = m5mols_write(sd, AE_MAN_GAIN_MON, val); + if (!ret) + ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val); + } return ret; + case V4L2_CID_AUTO_WHITE_BALANCE: - return m5mols_wb_mode(info, ctrl); + ret = m5mols_lock_awb(info, ctrl->val ? false : true); + if (!ret) + ret = m5mols_write(sd, AWB_MODE, ctrl->val ? + REG_AWB_AUTO : REG_AWB_PRESET); + return ret; + case V4L2_CID_SATURATION: - return m5mols_set_saturation(info, ctrl); + ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val); + if (!ret) + ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON); + return ret; + case V4L2_CID_COLORFX: - return m5mols_set_colorfx(info, ctrl); + /* + * This control uses two kinds of registers: normal & color. + * The normal effect belongs to category 1, while the color + * one belongs to category 2. + * + * The normal effect uses one register: CAT1_EFFECT. + * The color effect uses three registers: + * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB. + */ + ret = m5mols_write(sd, PARM_EFFECT, + ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA : + ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS : + REG_EFFECT_OFF); + if (!ret) + ret = m5mols_write(sd, MON_EFFECT, + ctrl->val == V4L2_COLORFX_SEPIA ? + REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF); + if (!ret) + ret = m5mols_write(sd, MON_CFIXR, + ctrl->val == V4L2_COLORFX_SEPIA ? + REG_CFIXR_SEPIA : 0); + if (!ret) + ret = m5mols_write(sd, MON_CFIXB, + ctrl->val == V4L2_COLORFX_SEPIA ? + REG_CFIXB_SEPIA : 0); + return ret; } return -EINVAL; diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index cf4c8ba..e0f09e5 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -1,5 +1,5 @@ /* - * Driver for M5MOLS 8M Pixel camera sensor with ISP + * Driver for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. * Author: HeungJun Kim <riverful.kim@samsung.com> @@ -18,11 +18,10 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/version.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/videodev2.h> -#include <linux/videodev2_exynos_media.h> +#include <linux/module.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> @@ -34,66 +33,35 @@ int m5mols_debug; module_param(m5mols_debug, int, 0644); -#define MOD_NAME "M5MOLS" -#define M5MOLS_I2C_CHECK_RETRY 50 -#define DEBUG -#define DEFAULT_SENSOR_WIDTH 800 -#define DEFAULT_SENSOR_HEIGHT 480 - -#define m5_err \ - do { printk("%s : %d : ret : %d\n", __func__, __LINE__, ret);\ - } while(0) -/* M5MOLS mode */ -static u8 m5mols_reg_mode[] = { - [MODE_SYSINIT] = 0x00, - [MODE_PARMSET] = 0x01, - [MODE_MONITOR] = 0x02, - [MODE_CAPTURE] = 0x03, - [MODE_UNKNOWN] = 0xff, -}; - -/* M5MOLS status */ -static u8 m5mols_reg_status[] = { - [STATUS_SYSINIT] = 0x00, - [STATUS_PARMSET] = 0x01, - [STATUS_MONITOR] = 0x02, - [STATUS_AUTO_FOCUS] = 0x03, - [STATUS_FACE_DETECTION] = 0x04, - [STATUS_DUAL_CAPTURE] = 0x05, - [STATUS_SINGLE_CAPTURE] = 0x06, - [STATUS_PREVIEW] = 0x07, - [STATUS_UNKNOWN] = 0xff, -}; +#define MODULE_NAME "M5MOLS" +#define M5MOLS_I2C_CHECK_RETRY 500 -/* M5MOLS regulator consumer names */ -/* The DEFAULT names of power are referenced with M5MO datasheet. */ +/* The regulator consumer names for external voltage regulators */ static struct regulator_bulk_data supplies[] = { { - /* core power - 1.2v, generally at the M5MOLS */ - .supply = "core", + .supply = "core", /* ARM core power, 1.2V */ }, { - .supply = "dig_18", /* digital power 1 - 1.8v */ + .supply = "dig_18", /* digital power 1, 1.8V */ }, { - .supply = "d_sensor", /* sensor power 1 - 1.8v */ + .supply = "d_sensor", /* sensor power 1, 1.8V */ }, { - .supply = "dig_28", /* digital power 2 - 2.8v */ + .supply = "dig_28", /* digital power 2, 2.8V */ }, { - .supply = "a_sensor", /* analog power */ + .supply = "a_sensor", /* analog power */ }, { - .supply = "dig_12", /* digital power 3 - 1.2v */ + .supply = "dig_12", /* digital power 3, 1.2V */ }, }; -/* M5MOLS default format (codes, sizes, preset values) */ -static struct v4l2_mbus_framefmt default_fmt[M5MOLS_RES_MAX] = { - [M5MOLS_RES_MON] = { - .width = DEFAULT_SENSOR_WIDTH, - .height = DEFAULT_SENSOR_HEIGHT, - .code = V4L2_MBUS_FMT_YUYV8_2X8, +static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { + [M5MOLS_RESTYPE_MONITOR] = { + .width = 1920, + .height = 1080, + .code = V4L2_MBUS_FMT_VYUY8_2X8, .field = V4L2_FIELD_NONE, .colorspace = V4L2_COLORSPACE_JPEG, }, - [M5MOLS_RES_CAPTURE] = { + [M5MOLS_RESTYPE_CAPTURE] = { .width = 1920, .height = 1080, .code = V4L2_MBUS_FMT_JPEG_1X8, @@ -101,201 +69,189 @@ static struct v4l2_mbus_framefmt default_fmt[M5MOLS_RES_MAX] = { .colorspace = V4L2_COLORSPACE_JPEG, }, }; - -#define SIZE_DEFAULT_FFMT ARRAY_SIZE(default_fmt) - -static const struct m5mols_format m5mols_formats[] = { - [M5MOLS_RES_MON] = { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - }, - [M5MOLS_RES_CAPTURE] = { - .code = V4L2_MBUS_FMT_JPEG_1X8, - .colorspace = V4L2_COLORSPACE_JPEG, - }, -}; - -static const struct m5mols_resolution m5mols_resolutions[] = { - /* monitor size */ - { 0x01, M5MOLS_RES_MON, 128, 96 }, /* SUB-QCIF */ - { 0x03, M5MOLS_RES_MON, 160, 120 }, /* QQVGA */ - { 0x05, M5MOLS_RES_MON, 176, 144 }, /* QCIF */ - { 0x06, M5MOLS_RES_MON, 176, 176 }, /* 176*176 */ - { 0x08, M5MOLS_RES_MON, 240, 320 }, /* 1 QVGA */ - { 0x09, M5MOLS_RES_MON, 320, 240 }, /* QVGA */ - { 0x0c, M5MOLS_RES_MON, 240, 400 }, /* l WQVGA */ - { 0x0d, M5MOLS_RES_MON, 400, 240 }, /* WQVGA */ - { 0x0e, M5MOLS_RES_MON, 352, 288 }, /* CIF */ - { 0x13, M5MOLS_RES_MON, 480, 360 }, /* 480*360 */ - { 0x15, M5MOLS_RES_MON, 640, 360 }, /* qHD */ - { 0x17, M5MOLS_RES_MON, 640, 480 }, /* VGA */ - { 0x18, M5MOLS_RES_MON, 720, 480 }, /* 720x480 */ - { 0x1a, M5MOLS_RES_MON, 800, 480 }, /* WVGA */ - { 0x1f, M5MOLS_RES_MON, 800, 600 }, /* SVGA */ - { 0x21, M5MOLS_RES_MON, 1280, 720 }, /* HD */ - { 0x25, M5MOLS_RES_MON, 1920, 1080 }, /* 1080p */ - { 0x29, M5MOLS_RES_MON, 3264, 2448 }, /* 8M (2.63fps@3264*2448) */ - { 0x30, M5MOLS_RES_MON, 320, 240 }, /* 60fps for slow motion */ - { 0x31, M5MOLS_RES_MON, 320, 240 }, /* 120fps for slow motion */ - { 0x39, M5MOLS_RES_MON, 800, 602 }, /* AHS_MON debug */ - - /* capture(JPEG or Bayer RAW or YUV Raw) size */ - { 0x02, M5MOLS_RES_CAPTURE, 320, 240 }, /* QVGA */ - { 0x04, M5MOLS_RES_CAPTURE, 400, 240 }, /* WQVGA */ - { 0x07, M5MOLS_RES_CAPTURE, 480, 360 }, /* 480 x 360 */ - { 0x08, M5MOLS_RES_CAPTURE, 640, 360 }, /* qHD */ - { 0x09, M5MOLS_RES_CAPTURE, 640, 480 }, /* VGA */ - { 0x0a, M5MOLS_RES_CAPTURE, 800, 480 }, /* WVGA */ - { 0x10, M5MOLS_RES_CAPTURE, 1280, 720 }, /* HD */ - { 0x14, M5MOLS_RES_CAPTURE, 1280, 960 }, /* 1M */ - { 0x17, M5MOLS_RES_CAPTURE, 1600, 1200 }, /* 2M */ - { 0x19, M5MOLS_RES_CAPTURE, 1920, 1080 }, /* Full-HD */ - { 0x1a, M5MOLS_RES_CAPTURE, 2048, 1152 }, /* 3M */ - { 0x1b, M5MOLS_RES_CAPTURE, 2048, 1536 }, /* 3M */ - { 0x1c, M5MOLS_RES_CAPTURE, 2560, 1440 }, /* 4M */ - { 0x1d, M5MOLS_RES_CAPTURE, 2560, 1536 }, /* 4M */ - { 0x1f, M5MOLS_RES_CAPTURE, 2560, 1920 }, /* 5M */ - { 0x21, M5MOLS_RES_CAPTURE, 3264, 1836 }, /* 6M */ - { 0x22, M5MOLS_RES_CAPTURE, 3264, 1960 }, /* 6M */ - { 0x25, M5MOLS_RES_CAPTURE, 3264, 2448 }, /* 8M */ -#ifdef M5MO_THUMB_SUPPORT - /* capture thumb(JPEG) size */ - { 0x00, M5MOLS_RES_THUMB, 160, 90 }, /* 160 x 90 */ - { 0x02, M5MOLS_RES_THUMB, 160, 120 }, /* QQVGA */ - { 0x04, M5MOLS_RES_THUMB, 320, 240 }, /* QVGA */ - { 0x06, M5MOLS_RES_THUMB, 400, 240 }, /* WQVGA */ - { 0x09, M5MOLS_RES_THUMB, 480, 360 }, /* 480 x 360 */ - { 0x0a, M5MOLS_RES_THUMB, 640, 360 }, /* qHD */ - { 0x0b, M5MOLS_RES_THUMB, 640, 480 }, /* VGA */ - { 0x0c, M5MOLS_RES_THUMB, 800, 480 }, /* WVGA */ -#endif -}; - -/* M5MOLS default FPS */ -static const struct v4l2_fract default_fps = { - .numerator = 1, - .denominator = M5MOLS_FPS_AUTO, +#define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) + +static const struct m5mols_resolution m5mols_reg_res[] = { + { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ + { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ + { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ + { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, + { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ + { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ + { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ + { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ + { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ + { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, + { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ + { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ + { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, + { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ + { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ + { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ + { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ + { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ + { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ + + { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ + { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ + { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, + { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ + { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ + { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ + { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ + { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ + { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ + { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ + { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ + { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, + { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ + { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, + { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ + { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ + { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, + { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ }; -static u8 m5mols_reg_fps[] = { - [M5MOLS_FPS_AUTO] = 0x01, - [M5MOLS_FPS_10] = 0x05, - [M5MOLS_FPS_12] = 0x04, - [M5MOLS_FPS_15] = 0x03, - [M5MOLS_FPS_20] = 0x08, - [M5MOLS_FPS_21] = 0x09, - [M5MOLS_FPS_22] = 0x0a, - [M5MOLS_FPS_23] = 0x0b, - [M5MOLS_FPS_24] = 0x07, - [M5MOLS_FPS_30] = 0x02, -}; - -static u32 m5mols_swap_byte(u8 *data, enum m5mols_i2c_size size) +/** + * m5mols_swap_byte - an byte array to integer conversion function + * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet + * + * Convert I2C data byte array with performing any required byte + * reordering to assure proper values for each data type, regardless + * of the architecture endianness. + */ +static u32 m5mols_swap_byte(u8 *data, u8 length) { - if (size == I2C_8BIT) + if (length == 1) return *data; - else if (size == I2C_16BIT) + else if (length == 2) return be16_to_cpu(*((u16 *)data)); else return be32_to_cpu(*((u32 *)data)); } -/* - * m5mols_read_reg/m5mols_write_reg - handle sensor's I2C communications. - * - * The I2C command packet of M5MOLS is made up 3 kinds of I2C bytes(category, - * command, bytes). Reference m5mols.h. - * - * The packet is needed 2, when M5MOLS is read through I2C. - * The packet is needed 1, when M5MOLS is written through I2C. - * - * I2C packet common order(including both reading/writing) - * 1st : size (data size + 4) - * 2nd : READ/WRITE (R - 0x01, W - 0x02) - * 3rd : Category - * 4th : Command - * - * I2C packet order for READING operation - * 5th : data real size for reading - * And, read another I2C packet again, until data size. - * - * I2C packet order for WRITING operation - * 5th to 8th: an actual data to write +/** + * m5mols_read - I2C read function + * @reg: combination of size, category and command for the I2C packet + * @size: desired size of I2C packet + * @val: read value */ - -#define M5MOLS_BYTE_READ 0x01 -#define M5MOLS_BYTE_WRITE 0x02 - -int m5mols_read_reg(struct v4l2_subdev *sd, - enum m5mols_i2c_size size, - u8 category, u8 cmd, u32 *val) +static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; + u8 category = I2C_CATEGORY(reg); + u8 cmd = I2C_COMMAND(reg); struct i2c_msg msg[2]; - u8 wbuf[5], rbuf[I2C_MAX + 1]; + u8 wbuf[5]; int ret; if (!client->adapter) return -ENODEV; - if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT) - return -EINVAL; - - /* 1st I2C operation for writing category & command. */ msg[0].addr = client->addr; msg[0].flags = 0; - msg[0].len = 5; /* 1(cmd size per bytes) + 4 */ + msg[0].len = 5; msg[0].buf = wbuf; - wbuf[0] = 5; /* same right above this */ + wbuf[0] = 5; wbuf[1] = M5MOLS_BYTE_READ; wbuf[2] = category; wbuf[3] = cmd; wbuf[4] = size; - /* 2nd I2C operation for reading data. */ msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].len = size + 1; msg[1].buf = rbuf; + /* minimum stabilization time */ + usleep_range(200, 200); + ret = i2c_transfer(client->adapter, msg, 2); if (ret < 0) { - m5_err; - dev_err(&client->dev, "failed READ[%d] at " - "cat[%02x] cmd[%02x]\n", - size, category, cmd); + v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", + size, category, cmd, ret); return ret; } *val = m5mols_swap_byte(&rbuf[1], size); - usleep_range(15000, 20000); /* must be for stabilization */ - return 0; } -int m5mols_write_reg(struct v4l2_subdev *sd, - enum m5mols_i2c_size size, - u8 category, u8 cmd, u32 val) +int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) +{ + u32 val_32; + int ret; + + if (I2C_SIZE(reg) != 1) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); + if (ret) + return ret; + + *val = (u8)val_32; + return ret; +} + +int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val) +{ + u32 val_32; + int ret; + + if (I2C_SIZE(reg) != 2) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); + if (ret) + return ret; + + *val = (u16)val_32; + return ret; +} + +int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) +{ + if (I2C_SIZE(reg) != 4) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + return m5mols_read(sd, I2C_SIZE(reg), reg, val); +} + +/** + * m5mols_write - I2C command write function + * @reg: combination of size, category and command for the I2C packet + * @val: value to write + */ +int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *cdev = &client->dev; - struct i2c_msg msg[1]; - u8 wbuf[I2C_MAX + 4]; + u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; + u8 category = I2C_CATEGORY(reg); + u8 cmd = I2C_COMMAND(reg); + u8 size = I2C_SIZE(reg); u32 *buf = (u32 *)&wbuf[4]; + struct i2c_msg msg[1]; int ret; if (!client->adapter) return -ENODEV; - if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT) { - dev_err(cdev, "Wrong data size\n"); + if (size != 1 && size != 2 && size != 4) { + v4l2_err(sd, "Wrong data size\n"); return -EINVAL; } msg->addr = client->addr; msg->flags = 0; - msg->len = size + 4; + msg->len = (u16)size + 4; msg->buf = wbuf; wbuf[0] = size + 4; wbuf[1] = M5MOLS_BYTE_WRITE; @@ -304,925 +260,547 @@ int m5mols_write_reg(struct v4l2_subdev *sd, *buf = m5mols_swap_byte((u8 *)&val, size); + usleep_range(200, 200); + ret = i2c_transfer(client->adapter, msg, 1); if (ret < 0) { - m5_err; - dev_err(&client->dev, "failed WRITE[%d] at " - "cat[%02x] cmd[%02x], ret %d\n", - size, msg->buf[2], msg->buf[3], ret); + v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n", + size, category, cmd, ret); return ret; } - usleep_range(15000, 20000); /* must be for stabilization */ - return 0; } -int m5mols_check_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value) +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask) { - u32 busy, i; + u8 busy; + int i; int ret; for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { - ret = m5mols_read_reg(sd, I2C_8BIT, category, cmd, &busy); + ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy); if (ret < 0) return ret; - - if (busy == value) /* bingo */ + if ((busy & mask) == mask) return 0; - - /* must be for stabilization */ - usleep_range(10000, 10000); } return -EBUSY; } -/* - * m5mols_set_mode - change and set mode of M5MOLS. +/** + * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts * - * This driver supports now only 3 modes(System, Monitor, Parameter). + * Before writing desired interrupt value the INT_FACTOR register should + * be read to clear pending interrupts. */ -int m5mols_set_mode(struct v4l2_subdev *sd, enum m5mols_mode mode) +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) { struct m5mols_info *info = to_m5mols(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *cdev = &client->dev; - const char *m5mols_str_mode[] = { - "System initialization", - "Parameter setting", - "Monitor setting", - "Capture setting", - "Unknown", - }; - int ret = 0; - - if (mode < MODE_SYSINIT || mode > MODE_UNKNOWN) - return -EINVAL; - - ret = i2c_w8_system(sd, CAT0_SYSMODE, m5mols_reg_mode[mode]); - if (!ret) { - /* bug detect, capture status is not 0x3 but 0x6 */ - if (mode == MODE_CAPTURE) - mode = STATUS_SINGLE_CAPTURE; - ret = m5mols_check_busy(sd, CAT_SYSTEM, CAT0_STATUS, - m5mols_reg_status[mode]); - if (ret) - m5_err; - } - if (ret < 0) - return ret; - - info->mode = m5mols_reg_mode[mode]; - dev_dbg(cdev, " mode: %s\n", m5mols_str_mode[mode]); + u8 mask = is_available_af(info) ? REG_INT_AF : 0; + u8 dummy; + int ret; + ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy); + if (!ret) + ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); return ret; } -/* - * m5mols_get_status - get status of M5MOLS. +/** + * m5mols_reg_mode - Write the mode and check busy status + * + * It always accompanies a little delay changing the M-5MOLS mode, so it is + * needed checking current busy status to guarantee right mode. */ -enum m5mols_status m5mols_get_status(struct v4l2_subdev *sd) +static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) { - struct m5mols_info *info = to_m5mols(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *cdev = &client->dev; - const char *m5mols_str_status[] = { - "System initialization", - "Parameter setting", - "Monitor setting", - "Auto Focus", - "Face Detection", - "Multi/Dual Capture", - "Single Capture", - "Preview (Data transfer)", /* It means recording, not preview. */ - "Unknown", - }; - u32 reg; - int ret = 0; + int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); - ret = i2c_r8_system(sd, CAT0_STATUS, ®); - if (ret) - return ret; - - if (reg < STATUS_SYSINIT || reg >= STATUS_UNKNOWN) - return -EINVAL; - - info->status = m5mols_reg_status[reg]; - dev_dbg(cdev, " status: %s\n", m5mols_str_status[reg]); - - return ret; + return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode); } -/* - * get_version - get M5MOLS sensor versions. +/** + * m5mols_mode - manage the M-5MOLS's mode + * @mode: the required operation mode + * + * The commands of M-5MOLS are grouped into specific modes. Each functionality + * can be guaranteed only when the sensor is operating in mode which which + * a command belongs to. */ -static int get_version(struct v4l2_subdev *sd) +int m5mols_mode(struct m5mols_info *info, u8 mode) { - struct m5mols_info *info = to_m5mols(sd); - union { - struct m5mols_version ver; - u8 bytes[10]; - } value; - int ret, i; - - for (i = CAT0_CUSTOMER_CODE; i <= CAT0_VERSION_AWB_L; i++) { - ret = i2c_r8_system(sd, i, (u32 *)&value.bytes[i]); - if (ret) - return ret; - } - - info->ver = value.ver; + struct v4l2_subdev *sd = &info->sd; + int ret = -EINVAL; + u8 reg; - info->ver.fw = be16_to_cpu(info->ver.fw); - info->ver.hw = be16_to_cpu(info->ver.hw); - info->ver.parm = be16_to_cpu(info->ver.parm); - info->ver.awb = be16_to_cpu(info->ver.awb); + if (mode < REG_PARAMETER || mode > REG_CAPTURE) + return ret; - return ret; -} + ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); + if ((!ret && reg == mode) || ret) + return ret; -static void m5mols_show_version(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *dev = &client->dev; - struct m5mols_info *info = to_m5mols(sd); + switch (reg) { + case REG_PARAMETER: + ret = m5mols_reg_mode(sd, REG_MONITOR); + if (!ret && mode == REG_MONITOR) + break; + if (!ret) + ret = m5mols_reg_mode(sd, REG_CAPTURE); + break; - dev_info(dev, "customer code\t0x%02x\n", info->ver.ctm_code); - dev_info(dev, "project code\t0x%02x\n", info->ver.pj_code); - dev_info(dev, "firmware version\t0x%04x\n", info->ver.fw); - dev_info(dev, "hardware version\t0x%04x\n", info->ver.hw); - dev_info(dev, "parameter version\t0x%04x\n", info->ver.parm); - dev_info(dev, "AWB version\t0x%04x\n", info->ver.awb); -} + case REG_MONITOR: + if (mode == REG_PARAMETER) { + ret = m5mols_reg_mode(sd, REG_PARAMETER); + break; + } -/* - * get_res_preset - find out M5MOLS register value from requested resolution. - * - * @width: requested width - * @height: requested height - * @type: requested type of each modes. It supports only monitor mode now. - */ -static int get_res_preset(struct v4l2_subdev *sd, u16 width, u16 height, - enum m5mols_res_type type) -{ - struct m5mols_info *info = to_m5mols(sd); - int i; + ret = m5mols_reg_mode(sd, REG_CAPTURE); + break; - for (i = 0; i < ARRAY_SIZE(m5mols_resolutions); i++) { - if ((m5mols_resolutions[i].type == type) && - (m5mols_resolutions[i].width == width) && - (m5mols_resolutions[i].height == height)) + case REG_CAPTURE: + ret = m5mols_reg_mode(sd, REG_MONITOR); + if (!ret && mode == REG_MONITOR) break; - } + if (!ret) + ret = m5mols_reg_mode(sd, REG_PARAMETER); + break; - if (i >= ARRAY_SIZE(m5mols_resolutions)) { - v4l2msg("no matching resolution\n"); - return -EINVAL; + default: + v4l2_warn(sd, "Wrong mode: %d\n", mode); } - return m5mols_resolutions[i].value; + if (!ret) + info->mode = mode; + + return ret; } -/* - * get_fps - calc & check FPS from v4l2_captureparm, if FPS is adequate, set. +/** + * m5mols_get_version - retrieve full revisions information of M-5MOLS * - * In M5MOLS case, the denominator means FPS. The each value of numerator and - * denominator should not be minus. If numerator is 0, it sets AUTO FPS. If - * numerator is not 1, it recalculates denominator. After it checks, the - * denominator is set to timeperframe.denominator, and used by FPS. + * The version information includes revisions of hardware and firmware, + * AutoFocus alghorithm version and the version string. */ -static int get_fps(struct v4l2_subdev *sd, - struct v4l2_captureparm *parm) +static int m5mols_get_version(struct v4l2_subdev *sd) { - int numerator = parm->timeperframe.numerator; - int denominator = parm->timeperframe.denominator; + struct m5mols_info *info = to_m5mols(sd); + struct m5mols_version *ver = &info->ver; + u8 *str = ver->str; + int i; + int ret; - /* The denominator should be +, except 0. The numerator shoud be +. */ - if (numerator < 0 || denominator <= 0) - return -EINVAL; + ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer); + if (!ret) + ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb); + if (!ret) + ret = m5mols_read_u8(sd, AF_VERSION, &ver->af); + if (ret) + return ret; - /* The numerator is 0, return auto fps. */ - if (numerator == 0) { - parm->timeperframe.denominator = M5MOLS_FPS_AUTO; - return 0; + for (i = 0; i < VERSION_STRING_SIZE; i++) { + ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]); + if (ret) + return ret; } - /* calc FPS(not time per frame) per 1 numerator */ - denominator = denominator / numerator; + ver->fw = be16_to_cpu(ver->fw); + ver->hw = be16_to_cpu(ver->hw); + ver->param = be16_to_cpu(ver->param); + ver->awb = be16_to_cpu(ver->awb); - if (denominator < M5MOLS_FPS_AUTO || denominator > M5MOLS_FPS_MAX) - return -EINVAL; + v4l2_info(sd, "Manufacturer\t[%s]\n", + is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? + "Samsung Electro-Machanics" : + is_manufacturer(info, REG_SAMSUNG_OPTICS) ? + "Samsung Fiber-Optics" : + is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? + "Samsung Techwin" : "None"); + v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", + info->ver.customer, info->ver.project); - if (!m5mols_reg_fps[denominator]) - return -EINVAL; + if (!is_available_af(info)) + v4l2_info(sd, "No support Auto Focus on this firmware\n"); - return 0; -} - -/* - * to_code - return pixelcode of M5MOLS according to resolution type. - */ -static enum v4l2_mbus_pixelcode to_code(enum m5mols_res_type res_type) -{ - return m5mols_formats[res_type].code; + return ret; } -/* - * to_res_type - return resolution type of M5MOLS according to pixelcode. +/** + * __find_restype - Lookup M-5MOLS resolution type according to pixel code + * @code: pixel code */ -static enum m5mols_res_type to_res_type(struct v4l2_subdev *sd, - enum v4l2_mbus_pixelcode code) +static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) { - int i = ARRAY_SIZE(m5mols_formats); + enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; - while (i--) - if (code == m5mols_formats[i].code) - break; - if (i < 0) - return M5MOLS_RES_MAX; + do { + if (code == m5mols_default_ffmt[type].code) + return type; + } while (type++ != SIZE_DEFAULT_FFMT); - if (code == m5mols_formats[M5MOLS_RES_MON].code) - return M5MOLS_RES_MON; - else - return M5MOLS_RES_CAPTURE; + return 0; } -static int m5mols_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *ffmt) +/** + * __find_resolution - Lookup preset and type of M-5MOLS's resolution + * @mf: pixel format to find/negotiate the resolution preset for + * @type: M-5MOLS resolution type + * @resolution: M-5MOLS resolution preset register value + * + * Find nearest resolution matching resolution preset and adjust mf + * to supported values. + */ +static int __find_resolution(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf, + enum m5mols_restype *type, + u32 *resolution) { - struct m5mols_info *info = to_m5mols(sd); - enum m5mols_res_type res_type; + const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; + const struct m5mols_resolution *match = NULL; + enum m5mols_restype stype = __find_restype(mf->code); + int i = ARRAY_SIZE(m5mols_reg_res); + unsigned int min_err = ~0; - res_type = to_res_type(sd, ffmt->code); - if (res_type == M5MOLS_RES_MAX) - return -EINVAL; + while (i--) { + int err; + if (stype == fsize->type) { + err = abs(fsize->width - mf->width) + + abs(fsize->height - mf->height); - *ffmt = info->fmt[res_type]; - info->code = ffmt->code; + if (err < min_err) { + min_err = err; + match = fsize; + } + } + fsize++; + } + if (match) { + mf->width = match->width; + mf->height = match->height; + *resolution = match->reg; + *type = stype; + return 0; + } - return 0; + return -EINVAL; } -static int m5mols_into_monitor(struct v4l2_subdev *sd, int res_size) +static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, + struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which, + enum m5mols_restype type) { - int ret; - - ret = m5mols_set_mode(sd, MODE_PARMSET); - if (!ret) - ret = i2c_w8_param(sd, CAT1_MONITOR_SIZE, (u8)res_size); - if (!ret) - ret = m5mols_set_mode(sd, MODE_PARMSET); + if (which == V4L2_SUBDEV_FORMAT_TRY) + return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; - return ret; + return &info->ffmt[type]; } -static int m5mols_into_capture(struct v4l2_subdev *sd, int res_size) +static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) { struct m5mols_info *info = to_m5mols(sd); - u32 reg; - int ret, timeout = 1; - u32 temp = 0; - - info->captured = false; - - /* - * The sequence of preparing Capture mode. - * 1. Clear Interrupt bit (for dummy) - * 2. Enable Capture bit at Interrupt - * 3. Lock AE/AWB - * 4. Enter Still Capture mode - */ - - ret = m5mols_set_mode(sd, MODE_MONITOR); - if (!ret) - /* FIXME: setting capture exposure at the middle of a amount. */ - ret = i2c_w16_ae(sd, CAT3_MANUAL_GAIN_CAP, 0x90); - if (!ret) - ret = m5mols_set_ae_lock(info, true); - if (!ret) - ret = m5mols_set_awb_lock(info, true); - if (!ret) - ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); - if (!ret) - ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 1 << INT_BIT_CAPTURE); - if (!ret) - ret = m5mols_set_mode(sd, MODE_CAPTURE); - if (!ret) - timeout = wait_event_interruptible_timeout(info->cap_wait, - info->captured, msecs_to_jiffies(2000)); - - /* disable all interrupt & clear interrupt */ - ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 0x0); - if (!ret) - ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); - if (ret) - return -EPERM; + struct v4l2_mbus_framefmt *format; - /* If all timeout exhausted, return error. */ - if (!timeout) - return -ETIMEDOUT; + format = __find_format(info, fh, fmt->which, info->res_type); + if (!format) + return -EINVAL; - ret = i2c_r32_capt_ctrl(sd, CATC_CAP_IMAGE_SIZE, &temp); - info->captured = false; - return ret; + fmt->format = *format; + return 0; } -static int m5mols_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *ffmt) +static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) { struct m5mols_info *info = to_m5mols(sd); - enum m5mols_res_type res_type; - int size; - int ret = -EINVAL; - - res_type = to_res_type(sd, ffmt->code); - if (res_type == M5MOLS_RES_MAX) - return -EINVAL; - - /* If user set portrait for preview, it is substitued width width height - * unless get_res_preset will fail that M5MOLS did not support - * reverse WVGA */ - if (ffmt->width < ffmt->height) { - int temp; - temp = ffmt->width; - ffmt->width = ffmt->height; - ffmt->height = temp; - } - size = get_res_preset(sd, ffmt->width, ffmt->height, res_type); - if (size < 0) - return -EINVAL; - - if (ffmt->code == m5mols_formats[M5MOLS_RES_MON].code) - ret = m5mols_into_monitor(sd, size); - else - ret = m5mols_into_capture(sd, 0); + struct v4l2_mbus_framefmt *format = &fmt->format; + struct v4l2_mbus_framefmt *sfmt; + enum m5mols_restype type; + u32 resolution = 0; + int ret; - info->fmt[res_type] = default_fmt[res_type]; - info->fmt[res_type].width = ffmt->width; - info->fmt[res_type].height = ffmt->height; + ret = __find_resolution(sd, format, &type, &resolution); + if (ret < 0) + return ret; - *ffmt = info->fmt[res_type]; - info->code = ffmt->code; + sfmt = __find_format(info, fh, fmt->which, type); + if (!sfmt) + return 0; - return ret; -} -static int m5mols_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (!code || index >= ARRAY_SIZE(m5mols_formats)) - return -EINVAL; + format->code = m5mols_default_ffmt[type].code; + format->colorspace = V4L2_COLORSPACE_JPEG; + format->field = V4L2_FIELD_NONE; - *code = m5mols_formats[index].code; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + *sfmt = *format; + info->resolution = resolution; + info->res_type = type; + } return 0; } -static int m5mols_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) { - struct m5mols_info *info = to_m5mols(sd); - struct v4l2_captureparm *cp = &parms->parm.capture; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + if (!code || code->index >= SIZE_DEFAULT_FFMT) return -EINVAL; - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe = info->tpf; + code->code = m5mols_default_ffmt[code->index].code; return 0; } -static int m5mols_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static struct v4l2_subdev_pad_ops m5mols_pad_ops = { + .enum_mbus_code = m5mols_enum_mbus_code, + .get_fmt = m5mols_get_fmt, + .set_fmt = m5mols_set_fmt, +}; + +/** + * m5mols_sync_controls - Apply default scene mode and the current controls + * + * This is used only streaming for syncing between v4l2_ctrl framework and + * m5mols's controls. First, do the scenemode to the sensor, then call + * v4l2_ctrl_handler_setup. It can be same between some commands and + * the scenemode's in the default v4l2_ctrls. But, such commands of control + * should be prior to the scenemode's one. + */ +int m5mols_sync_controls(struct m5mols_info *info) { - struct m5mols_info *info = to_m5mols(sd); - struct v4l2_captureparm *cp = &parms->parm.capture; int ret = -EINVAL; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; + if (!is_ctrl_synced(info)) { + ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); + if (ret) + return ret; - ret = m5mols_set_mode_backup(sd, MODE_PARMSET); - if (!ret) - ret = get_fps(sd, cp); /* set right FPS to denominator. */ - if (!ret) - ret = i2c_w8_param(sd, CAT1_MONITOR_FPS, - m5mols_reg_fps[cp->timeperframe.denominator]); - if (!ret) - ret = m5mols_set_mode_restore(sd); - if (!ret) { - cp->capability = V4L2_CAP_TIMEPERFRAME; - info->tpf = cp->timeperframe; + v4l2_ctrl_handler_setup(&info->handle); + info->ctrl_sync = true; } - v4l2msg("denominator: %d / numerator: %d.\n", - cp->timeperframe.denominator, cp->timeperframe.numerator); - return ret; } -static int m5mols_get_info_capture(struct v4l2_subdev *sd) +/** + * m5mols_start_monitor - Start the monitor mode + * + * Before applying the controls setup the resolution and frame rate + * in PARAMETER mode, and then switch over to MONITOR mode. + */ +static int m5mols_start_monitor(struct m5mols_info *info) { - struct m5mols_info *info = to_m5mols(sd); - struct m5mols_exif *exif = &info->cap.exif; - int denominator, numerator; - int ret = 0; - - ret = i2c_r32_exif(sd, CAT7_INFO_EXPTIME_NU, &numerator); - if (!ret) - ret = i2c_r32_exif(sd, CAT7_INFO_EXPTIME_DE, &denominator); - if (!ret) - exif->exposure_time = (u32)(numerator / denominator); - if (ret) - return ret; - - ret = i2c_r32_exif(sd, CAT7_INFO_TV_NU, &numerator); - if (!ret) - ret = i2c_r32_exif(sd, CAT7_INFO_TV_DE, &denominator); - if (!ret) - exif->shutter_speed = (u32)(numerator / denominator); - if (ret) - return ret; - - ret = i2c_r32_exif(sd, CAT7_INFO_AV_NU, &numerator); - if (!ret) - ret = i2c_r32_exif(sd, CAT7_INFO_AV_DE, &denominator); - if (!ret) - exif->aperture = (u32)(numerator / denominator); - if (ret) - return ret; - - ret = i2c_r32_exif(sd, CAT7_INFO_BV_NU, &numerator); - if (!ret) - ret = i2c_r32_exif(sd, CAT7_INFO_BV_DE, &denominator); - if (!ret) - exif->brightness = (u32)(numerator / denominator); - if (ret) - return ret; - - ret = i2c_r32_exif(sd, CAT7_INFO_EBV_NU, &numerator); - if (!ret) - ret = i2c_r32_exif(sd, CAT7_INFO_EBV_DE, &denominator); - if (!ret) - exif->exposure_bias = (u32)(numerator / denominator); - if (ret) - return ret; + struct v4l2_subdev *sd = &info->sd; + int ret; - ret = i2c_r16_exif(sd, CAT7_INFO_ISO, (u32 *)&exif->iso_speed); - if (!ret) - ret = i2c_r16_exif(sd, CAT7_INFO_FLASH, (u32 *)&exif->flash); + ret = m5mols_mode(info, REG_PARAMETER); if (!ret) - ret = i2c_r16_exif(sd, CAT7_INFO_SDR, (u32 *)&exif->sdr); + ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); if (!ret) - ret = i2c_r16_exif(sd, CAT7_INFO_QVAL, (u32 *)&exif->qval); - if (ret) - return ret; + ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); if (!ret) - ret = i2c_r32_capt_ctrl(sd, CATC_CAP_IMAGE_SIZE, - &info->cap.main); + ret = m5mols_mode(info, REG_MONITOR); if (!ret) - ret = i2c_r32_capt_ctrl(sd, CATC_CAP_THUMB_SIZE, - &info->cap.thumb); - - info->cap.total = info->cap.main + info->cap.thumb; - - v4l2_info(sd, "%s: capture total size %d\n", __func__, info->cap.total); - v4l2_info(sd, "%s: capture main size %d\n", __func__, info->cap.main); - v4l2_info(sd, "%s: capture thumb size %d\n", __func__, info->cap.thumb); - v4l2_info(sd, "%s: exposure_time %d\n", __func__, exif->exposure_time); - v4l2_info(sd, "%s: shutter_speed %d\n", __func__, exif->shutter_speed); - v4l2_info(sd, "%s: aperture %d\n", __func__, exif->aperture); - v4l2_info(sd, "%s: brightness %d\n", __func__, exif->brightness); - v4l2_info(sd, "%s: exposure_bias %d\n", __func__, exif->exposure_bias); - v4l2_info(sd, "%s: iso_speed %d\n", __func__, exif->iso_speed); - v4l2_info(sd, "%s: flash %d\n", __func__, exif->flash); - v4l2_info(sd, "%s: sdr %d\n", __func__, exif->sdr); - v4l2_info(sd, "%s: qval %d\n", __func__, exif->qval); + ret = m5mols_sync_controls(info); return ret; } -/* TODO: not verified. */ -static int m5mols_start_capture(struct v4l2_subdev *sd) +static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) { struct m5mols_info *info = to_m5mols(sd); - u32 reg, size; - int ret, timeout; - - u8 reg_capt_fmt[] = { - 0x10, /* JPEG with header + Thumbnail JPEG(YUV422@QVGA) */ - }; /* YUV422, JPEG(422), JPEG(420) */ - info->captured = false; - - size = get_res_preset(sd, - info->fmt[M5MOLS_RES_CAPTURE].width, - info->fmt[M5MOLS_RES_CAPTURE].height, - M5MOLS_RES_CAPTURE); - if (size < 0) - return -EINVAL; - ret = 0; - /* - * The sequence of Starting Capture mode. - * 1. Select capture Single or Multi - * 2. Select format (YUV422, JPEG(YUV420, YUV422)) - * 3. Set image size preset of Capture - * 4. Read Interrupt bit (for dummy) - * 5. Enable Capture bit at Interrupt - * 6. Start Capture - * 7. Check interrupt and register value - * 8. Get Image & Thumb size - */ - ret = i2c_w8_capt_ctrl(sd, CATC_CAP_SEL_FRAME, true); /* single capture */ - if (!ret) - ret = i2c_w8_capt_parm(sd, CATB_YUVOUT_MAIN, reg_capt_fmt[0]); - if (!ret) - ret = i2c_w8_capt_parm(sd, CATB_MAIN_IMAGE_SIZE, size); - if (!ret) - ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); - if (!ret) - ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 1 << INT_BIT_CAPTURE); - if (!ret) - ret = i2c_w8_capt_ctrl(sd, CATC_CAP_START, true); - if (!ret) { - timeout = wait_event_interruptible_timeout(info->cap_wait, - info->captured, msecs_to_jiffies(2000)); - - if (info->captured) { - ret = m5mols_get_info_capture(sd); + u32 code = info->ffmt[info->res_type].code; - if (!ret) - v4l2_subdev_notify(sd, info->cap.total, NULL); - else - return ret; - } - - /* disable all interrupt & clear interrupt */ - ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 0x0); - if (!ret) - ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); - if (ret) - return -EPERM; - - /* If all timeout exhausted, return error. */ - if (!timeout) - return -ETIMEDOUT; + if (enable) { + int ret = -EINVAL; - info->captured = false; + if (is_code(code, M5MOLS_RESTYPE_MONITOR)) + ret = m5mols_start_monitor(info); + if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) + ret = m5mols_start_capture(info); - ret = 0; + return ret; } - /* TODO: complete capture. */ - - return ret; -} - -static int m5mols_start_monitor(struct v4l2_subdev *sd) -{ - return m5mols_set_mode(sd, MODE_MONITOR); -} - -static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct m5mols_info *info = to_m5mols(sd); - - if (enable) { - if (info->code == to_code(M5MOLS_RES_MON)) { - v4l2_info(sd, "%s : monitor mode\n", __func__); - return m5mols_start_monitor(sd); - } - if (info->code == to_code(M5MOLS_RES_CAPTURE)) { - v4l2_info(sd, "%s : capture mode\n", __func__); - return m5mols_start_capture(sd); - } - return -EINVAL; - } else { - if (is_streaming(sd)) - return m5mols_set_mode(sd, MODE_PARMSET); - return -EINVAL; - } + return m5mols_mode(info, REG_PARAMETER); } static const struct v4l2_subdev_video_ops m5mols_video_ops = { - .g_mbus_fmt = m5mols_g_mbus_fmt, - .s_mbus_fmt = m5mols_s_mbus_fmt, - .enum_mbus_fmt = m5mols_enum_mbus_fmt, - .g_parm = m5mols_g_parm, - .s_parm = m5mols_s_parm, - .s_stream = m5mols_s_stream, + .s_stream = m5mols_s_stream, }; static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); + struct m5mols_info *info = to_m5mols(sd); int ret; - ret = m5mols_set_mode_backup(sd, MODE_PARMSET); + info->mode_save = info->mode; + + ret = m5mols_mode(info, REG_PARAMETER); if (!ret) ret = m5mols_set_ctrl(ctrl); if (!ret) - ret = m5mols_set_mode_restore(sd); - - return ret; -} - -static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct m5mols_info *info = to_m5mols(sd); - int ret = 0; + ret = m5mols_mode(info, info->mode_save); - switch (ctrl->id) { - case V4L2_CID_CAM_JPEG_ENCODEDSIZE: - ctrl->cur.val = info->cap.total; - break; - default: - ret = -EINVAL; - break; - } return ret; } static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { - .s_ctrl = m5mols_s_ctrl, - .g_volatile_ctrl = m5mols_g_volatile_ctrl, + .s_ctrl = m5mols_s_ctrl, }; -static const struct v4l2_ctrl_config ctrl_private[] = { - { - .ops = &m5mols_ctrl_ops, - .id = V4L2_CID_CAM_JPEG_MEMSIZE, - .name = "Jpeg memory size", - .type = V4L2_CTRL_TYPE_INTEGER, - .flags = V4L2_CTRL_FLAG_SLIDER, - .max = M5MO_JPEG_MEMSIZE, - .step = 1, - .min = 0, - .def = M5MO_JPEG_MEMSIZE, - .is_private = 1, - }, { - .ops = &m5mols_ctrl_ops, - .id = V4L2_CID_CAM_JPEG_ENCODEDSIZE, - .name = "Jpeg encoded size", - .type = V4L2_CTRL_TYPE_INTEGER, - .flags = V4L2_CTRL_FLAG_SLIDER, - .max = M5MO_JPEG_MEMSIZE, - .step = 1, - .min = 0, - .def = 0, - .is_private = 1, - .is_volatile = 1, - }, -}; -/* - * m5mols_sensor_power - handle sensor power up/down. - * - * @enable: If it is true, power up. If is not, power down. - */ static int m5mols_sensor_power(struct m5mols_info *info, bool enable) { struct v4l2_subdev *sd = &info->sd; - struct i2c_client *c = v4l2_get_subdevdata(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct m5mols_platform_data *pdata = info->pdata; int ret; if (enable) { - if (is_powerup(sd)) + if (is_powered(info)) return 0; - /* power-on additional power */ if (info->set_power) { - ret = info->set_power(&c->dev, 1); + ret = info->set_power(&client->dev, 1); if (ret) return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); - if (ret) + if (ret) { + info->set_power(&client->dev, 0); return ret; + } - gpio_set_value(info->pdata->gpio_rst, info->pdata->enable_rst); + gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); usleep_range(1000, 1000); - info->power = true; - } else { - if (!is_powerup(sd)) - return 0; - ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); - if (ret) - return ret; + return ret; + } - /* power-off additional power */ - if (info->set_power) { - ret = info->set_power(&c->dev, 0); - if (ret) - return ret; - } + if (!is_powered(info)) + return 0; - info->power = false; + ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); + if (ret) + return ret; - gpio_set_value(info->pdata->gpio_rst, !info->pdata->enable_rst); - usleep_range(1000, 1000); - } + if (info->set_power) + info->set_power(&client->dev, 0); - return ret; -} + gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); + usleep_range(1000, 1000); + info->power = false; -static void m5mols_irq_work(struct work_struct *work) -{ - struct m5mols_info *info = container_of(work, struct m5mols_info, work); - struct v4l2_subdev *sd = &info->sd; - u32 reg; - int ret; - if (is_powerup(sd)) { - ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); - if (!ret) { - switch (reg & 0x0f) { - case (1 << INT_BIT_AF): - /* Except returning zero at just that upper - * statments, not entering in this parenthesis. - * The return value is below: - * 0x0 : AF Fail - * 0x2 : AF Success - * 0x4 : Idle Status - * 0x5 : Busy Status */ - ret = i2c_r8_lens(sd, CATA_AF_STATUS, ®); - if (!ret && (reg == 0x02)) - info->is_focus = true; - else - info->is_focus = false; - printk("%s = AF %02x, focus %d\n", - __func__, reg, info->is_focus); - break; - case (1 << INT_BIT_CAPTURE): - printk("%s = CAPTURE\n", __func__); - if (!info->captured) { - wake_up_interruptible(&info->cap_wait); - info->captured = true; - } - break; - case (1 << INT_BIT_ZOOM): - case (1 << INT_BIT_FRAME_SYNC): - case (1 << INT_BIT_FD): - case (1 << INT_BIT_LENS_INIT): - case (1 << INT_BIT_SOUND): - printk("%s = Nothing : 0x%08x\n", __func__, reg); - break; - case (1 << INT_BIT_MODE): - default: - break; - } - } - } + return ret; } -static irqreturn_t m5mols_irq_handler(int irq, void *data) +/* m5mols_update_fw - optional firmware update routine */ +int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, + int (*set_power)(struct m5mols_info *, bool)) { - struct v4l2_subdev *sd = data; - struct m5mols_info *info = to_m5mols(sd); - - v4l2_info(sd, "%s\n", __func__); - - schedule_work(&info->work); - - return IRQ_HANDLED; + return 0; } -/* - * m5mols_sensor_armboot - booting M5MOLS internal ARM core-controller. +/** + * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core. * - * It makes to ready M5MOLS for I2C & MIPI interface. After it's powered up, - * it activates if it gets armboot command for I2C interface. After getting - * cmd, it must wait about least 500ms referenced by M5MOLS datasheet. + * Booting internal ARM core makes the M-5MOLS is ready for getting commands + * with I2C. It's the first thing to be done after it powered up. It must wait + * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting. */ static int m5mols_sensor_armboot(struct v4l2_subdev *sd) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct m5mols_info *info = to_m5mols(sd); - static u8 m5mols_mipi_value = 0x02; - u32 reg; int ret; - /* 1. ARM booting */ - ret = i2c_w8_flash(sd, CATC_CAM_START, true); + ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); if (ret < 0) return ret; - msleep(500); - dev_dbg(&client->dev, "Success ARM Booting\n"); + msleep(520); - /* after ARM booting, the M5MOLS state changed Parameter mode. */ - info->mode = MODE_PARMSET; - - ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); /* clear intterupt */ - if (!ret) - ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 0x0); /* all disable */ - if (!ret) - ret = get_version(sd); + ret = m5mols_get_version(sd); if (!ret) - ret = i2c_w8_param(sd, CAT1_DATA_INTERFACE, m5mols_mipi_value); + ret = m5mols_update_fw(sd, m5mols_sensor_power); + if (ret) + return ret; - m5mols_show_version(sd); + v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); + + ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); + if (!ret) + ret = m5mols_enable_interrupt(sd, REG_INT_AF); return ret; } -/* - * m5mols_init_controls - initialization using v4l2_ctrl. - */ static int m5mols_init_controls(struct m5mols_info *info) { struct v4l2_subdev *sd = &info->sd; - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 max_ex_mon; + u16 max_exposure; + u16 step_zoom; int ret; - /* check minimum & maximum of M5MOLS controls */ - ret = i2c_r16_ae(sd, CAT3_MAX_GAIN_MON, (u32 *)&max_ex_mon); + /* Determine value's range & step of controls for various FW version */ + ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure); + if (!ret) + step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; if (ret) return ret; - /* set the controls using v4l2 control frameworks */ - v4l2_ctrl_handler_init(&info->handle, 9); - - info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, - &m5mols_ctrl_ops, V4L2_CID_COLORFX, - 9, 1, V4L2_COLORFX_NONE); - info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, - &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, - 1, 0, V4L2_EXPOSURE_AUTO); - info->exposure = v4l2_ctrl_new_std(&info->handle, - &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, - 0, max_ex_mon, 1, (int)max_ex_mon/2); - info->autofocus = v4l2_ctrl_new_std(&info->handle, - &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO, - 0, 1, 1, 0); + v4l2_ctrl_handler_init(&info->handle, 6); info->autowb = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, - 0, 1, 1, 1); + 0, 1, 1, 0); info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, V4L2_CID_SATURATION, - 0, 6, 1, 3); + 1, 5, 1, 3); info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE, - 0, 70, 1, 0); - info->jpeg_size = v4l2_ctrl_new_custom(&info->handle, - &ctrl_private[0], - NULL); - info->encoded_size = v4l2_ctrl_new_custom(&info->handle, - &ctrl_private[1], - NULL); + 1, 70, step_zoom, 1); + info->exposure = v4l2_ctrl_new_std(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, + 0, max_exposure, 1, (int)max_exposure/2); + info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_COLORFX, + 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); + info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, + 1, 0, V4L2_EXPOSURE_MANUAL); sd->ctrl_handler = &info->handle; - if (info->handle.error) { - dev_err(&client->dev, "Failed to init controls, %d\n", ret); + v4l2_err(sd, "Failed to initialize controls: %d\n", ret); v4l2_ctrl_handler_free(&info->handle); return info->handle.error; } v4l2_ctrl_cluster(2, &info->autoexposure); - /* If above ctrl value is not good image, so it is better that not set */ - v4l2_ctrl_handler_setup(&info->handle); return 0; } -/* - * m5mols_setup_default - set default size & fps in the monitor mode. +/** + * m5mols_s_power - Main sensor power control function + * + * To prevent breaking the lens when the sensor is powered off the Soft-Landing + * algorithm is called where available. The Soft-Landing algorithm availability + * dependends on the firmware provider. */ -static int m5mols_setup_default(struct v4l2_subdev *sd) -{ - struct m5mols_info *info = to_m5mols(sd); - int value; - int ret = -EINVAL; - - value = get_res_preset(sd, - default_fmt[M5MOLS_RES_MON].width, - default_fmt[M5MOLS_RES_MON].height, - M5MOLS_RES_MON); - if (value >= 0) - ret = i2c_w8_param(sd, CAT1_MONITOR_SIZE, (u8)value); - if (!ret) - ret = i2c_w8_param(sd, CAT1_MONITOR_FPS, - m5mols_reg_fps[default_fps.denominator]); - if (!ret) - ret = m5mols_init_controls(info); - if (!ret) - ret = m5mols_set_ae_lock(info, false); - if (!ret) - ret = m5mols_set_awb_lock(info, false); - if (!ret) { - info->fmt[M5MOLS_RES_MON] = default_fmt[M5MOLS_RES_MON]; - info->tpf = default_fps; - - ret = 0; - } - - return ret; -} - static int m5mols_s_power(struct v4l2_subdev *sd, int on) { struct m5mols_info *info = to_m5mols(sd); @@ -1233,9 +811,34 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on) if (!ret) ret = m5mols_sensor_armboot(sd); if (!ret) - ret = m5mols_setup_default(sd); - } else { - ret = m5mols_sensor_power(info, false); + ret = m5mols_init_controls(info); + if (ret) + return ret; + + info->ffmt[M5MOLS_RESTYPE_MONITOR] = + m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; + info->ffmt[M5MOLS_RESTYPE_CAPTURE] = + m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; + return ret; + } + + if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { + ret = m5mols_mode(info, REG_MONITOR); + if (!ret) + ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); + if (!ret) + ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); + if (!ret) + ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, + REG_AF_IDLE); + if (!ret) + v4l2_info(sd, "Success soft-landing lens\n"); + } + + ret = m5mols_sensor_power(info, false); + if (!ret) { + v4l2_ctrl_handler_free(&info->handle); + info->ctrl_sync = false; } return ret; @@ -1251,334 +854,168 @@ static int m5mols_log_status(struct v4l2_subdev *sd) } static const struct v4l2_subdev_core_ops m5mols_core_ops = { - .s_power = m5mols_s_power, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .log_status = m5mols_log_status, -}; - -/** - * __find_restype - Lookup M-5MOLS resolution type according to pixel code - * @code: pixel code - */ -static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) -{ - enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; - - do { - if (code == default_fmt[type].code) - return type; - } while (type++ != SIZE_DEFAULT_FFMT); - - return 0; -} - -/** - * __find_resolution - Lookup preset and type of M-5MOLS's resolution - * @mf: pixel format to find/negotiate the resolution preset for - * @type: M-5MOLS resolution type - * @resolution: M-5MOLS resolution preset register value - * - * Find nearest resolution matching resolution preset and adjust mf - * to supported values. - */ -static int __find_resolution(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf, - enum m5mols_restype *type, - u32 *resolution) -{ - const struct m5mols_resolution *fsize = &m5mols_resolutions[0]; - const struct m5mols_resolution *match = NULL; - enum m5mols_restype stype = __find_restype(mf->code); - int i = ARRAY_SIZE(m5mols_resolutions); - unsigned int min_err = ~0; - - while (i--) { - int err; - if (stype == fsize->type) { - err = abs(fsize->width - mf->width) - + abs(fsize->height - mf->height); - - if (err < min_err) { - min_err = err; - match = fsize; - } - } - fsize++; - } - if (match) { - mf->width = match->width; - mf->height = match->height; - *resolution = match->value; - *type = stype; - return 0; - } - - return -EINVAL; -} - -static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, - struct v4l2_subdev_fh *fh, - enum v4l2_subdev_format_whence which, - enum m5mols_restype type) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; - - return &info->fmt[type]; -} - -static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct m5mols_info *info = to_m5mols(sd); - struct v4l2_mbus_framefmt *format; - - if (fmt->pad != 0) - return -EINVAL; - - format = __find_format(info, fh, fmt->which, info->res_type); - if (!format) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct m5mols_info *info = to_m5mols(sd); - struct v4l2_mbus_framefmt *format = &fmt->format; - struct v4l2_mbus_framefmt *sfmt; - enum m5mols_restype type; - u32 resolution = 0; - int ret; - - if (fmt->pad != 0) - return -EINVAL; - - ret = __find_resolution(sd, format, &type, &resolution); - if (ret < 0) - return ret; - - sfmt = __find_format(info, fh, fmt->which, type); - if (!sfmt) - return 0; - - sfmt = &default_fmt[type]; - sfmt->width = format->width; - sfmt->height = format->height; - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - info->resolution = resolution; - info->code = format->code; - info->res_type = type; - } - - return 0; -} - -static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (!code || code->index >= SIZE_DEFAULT_FFMT) - return -EINVAL; - - code->code = default_fmt[code->index].code; - - return 0; -} - -static struct v4l2_subdev_pad_ops m5mols_pad_ops = { - .enum_mbus_code = m5mols_enum_mbus_code, - .get_fmt = m5mols_get_fmt, - .set_fmt = m5mols_set_fmt, + .s_power = m5mols_s_power, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .log_status = m5mols_log_status, }; static const struct v4l2_subdev_ops m5mols_ops = { - .core = &m5mols_core_ops, - .pad = &m5mols_pad_ops, - .video = &m5mols_video_ops, + .core = &m5mols_core_ops, + .pad = &m5mols_pad_ops, + .video = &m5mols_video_ops, }; -static int m5mols_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - printk("%s\n", __func__); - return 0; -} -static const struct media_entity_operations m5mols_media_ops = { - .link_setup = m5mols_link_setup, -}; - -static int m5mols_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +static void m5mols_irq_work(struct work_struct *work) { - struct v4l2_subdev_format format; + struct m5mols_info *info = + container_of(work, struct m5mols_info, work_irq); + struct v4l2_subdev *sd = &info->sd; + u8 reg; + int ret; - memset(&format, 0, sizeof(format)); - format.pad = 0; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = m5mols_formats[M5MOLS_RES_MON].code; - format.format.width = DEFAULT_SENSOR_WIDTH; - format.format.height = DEFAULT_SENSOR_HEIGHT; + if (!is_powered(info) || + m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) + return; - m5mols_set_fmt(sd, fh, &format); + switch (info->interrupt & REG_INT_MASK) { + case REG_INT_AF: + if (!is_available_af(info)) + break; + ret = m5mols_read_u8(sd, AF_STATUS, ®); + v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", + reg == REG_AF_FAIL ? "Failed" : + reg == REG_AF_SUCCESS ? "Success" : + reg == REG_AF_IDLE ? "Idle" : "Busy"); + break; + case REG_INT_CAPTURE: + if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) + wake_up_interruptible(&info->irq_waitq); - return 0; + v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); + break; + default: + v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); + break; + }; } -static int m5mols_subdev_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) +static irqreturn_t m5mols_irq_handler(int irq, void *data) { - v4l2_dbg(1, m5mols_debug, sd, "%s", __func__); - return 0; -} + struct v4l2_subdev *sd = data; + struct m5mols_info *info = to_m5mols(sd); -static int m5mols_subdev_registered(struct v4l2_subdev *sd) -{ - v4l2_dbg(1, m5mols_debug, sd, "%s", __func__); - return 0; -} + schedule_work(&info->work_irq); -static void m5mols_subdev_unregistered(struct v4l2_subdev *sd) -{ - v4l2_dbg(1, m5mols_debug, sd, "%s", __func__); + return IRQ_HANDLED; } -static const struct v4l2_subdev_internal_ops m5mols_v4l2_internal_ops = { - .open = m5mols_init_formats, - .close = m5mols_subdev_close, - .registered = m5mols_subdev_registered, - .unregistered = m5mols_subdev_unregistered, -}; - -static int m5mols_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int __devinit m5mols_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - const struct m5mols_platform_data *pdata = - client->dev.platform_data; + const struct m5mols_platform_data *pdata = client->dev.platform_data; struct m5mols_info *info; struct v4l2_subdev *sd; - int ret = 0; + int ret; if (pdata == NULL) { dev_err(&client->dev, "No platform data\n"); return -EINVAL; } - if (!gpio_is_valid(pdata->gpio_rst)) { - dev_err(&client->dev, "No valid nRST gpio pin.\n"); + if (!gpio_is_valid(pdata->gpio_reset)) { + dev_err(&client->dev, "No valid RESET GPIO specified\n"); return -EINVAL; } - if (!pdata->irq) { - dev_err(&client->dev, "Interrupt not assigned.\n"); + if (!client->irq) { + dev_err(&client->dev, "Interrupt not assigned\n"); return -EINVAL; } info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); - if (info == NULL) { - dev_err(&client->dev, "Failed to allocate info\n"); + if (!info) return -ENOMEM; - } - info->pdata = pdata; - if (info->pdata->set_power) /* for additional power if needed. */ - info->set_power = pdata->set_power; + info->pdata = pdata; + info->set_power = pdata->set_power; - if (info->pdata->irq) { - INIT_WORK(&info->work, m5mols_irq_work); - ret = request_irq(info->pdata->irq, m5mols_irq_handler, - IRQF_TRIGGER_RISING, MOD_NAME, &info->sd); - if (ret) { - dev_err(&client->dev, "Failed to request irq: %d\n", ret); - return ret; - } - } - - ret = gpio_request(info->pdata->gpio_rst, "M5MOLS nRST"); + ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); if (ret) { - dev_err(&client->dev, "Failed to set gpio, %d\n", ret); - goto out_gpio; + dev_err(&client->dev, "Failed to request gpio: %d\n", ret); + goto out_free; } - - gpio_direction_output(info->pdata->gpio_rst, !info->pdata->enable_rst); + gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); if (ret) { - dev_err(&client->dev, "Failed to get regulators, %d\n", ret); - goto out_reg; + dev_err(&client->dev, "Failed to get regulators: %d\n", ret); + goto out_gpio; } sd = &info->sd; - strlcpy(sd->name, MOD_NAME, sizeof(sd->name)); - - init_waitqueue_head(&info->cap_wait); - + strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); v4l2_i2c_subdev_init(sd, client, &m5mols_ops); + info->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, 1, &info->pad, 0); if (ret < 0) goto out_reg; - - m5mols_init_formats(sd, NULL); - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - sd->internal_ops = &m5mols_v4l2_internal_ops; - sd->entity.ops = &m5mols_media_ops; + init_waitqueue_head(&info->irq_waitq); + INIT_WORK(&info->work_irq, m5mols_irq_work); + ret = request_irq(client->irq, m5mols_irq_handler, + IRQF_TRIGGER_RISING, MODULE_NAME, sd); + if (ret) { + dev_err(&client->dev, "Interrupt request failed: %d\n", ret); + goto out_me; + } info->res_type = M5MOLS_RESTYPE_MONITOR; - - v4l2_info(sd, "%s : m5mols driver probed success\n", __func__); - return 0; - +out_me: + media_entity_cleanup(&sd->entity); out_reg: regulator_bulk_free(ARRAY_SIZE(supplies), supplies); out_gpio: - gpio_free(info->pdata->gpio_rst); + gpio_free(pdata->gpio_reset); +out_free: kfree(info); - return ret; } -static int m5mols_remove(struct i2c_client *client) +static int __devexit m5mols_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct m5mols_info *info = to_m5mols(sd); v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&info->handle); - free_irq(info->pdata->irq, sd); + free_irq(client->irq, sd); + regulator_bulk_free(ARRAY_SIZE(supplies), supplies); - gpio_free(info->pdata->gpio_rst); + gpio_free(info->pdata->gpio_reset); media_entity_cleanup(&sd->entity); kfree(info); - return 0; } static const struct i2c_device_id m5mols_id[] = { - { MOD_NAME, 0 }, + { MODULE_NAME, 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, m5mols_id); static struct i2c_driver m5mols_i2c_driver = { .driver = { - .name = MOD_NAME, + .name = MODULE_NAME, }, .probe = m5mols_probe, - .remove = m5mols_remove, + .remove = __devexit_p(m5mols_remove), .id_table = m5mols_id, }; @@ -1597,5 +1034,5 @@ module_exit(m5mols_mod_exit); MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); -MODULE_DESCRIPTION("Fujitsu M5MOLS 8M Pixel camera sensor with ISP driver"); +MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h index da9cab5..c755bd6 100644 --- a/drivers/media/video/m5mols/m5mols_reg.h +++ b/drivers/media/video/m5mols/m5mols_reg.h @@ -1,5 +1,5 @@ /* - * Register map for M5MOLS 8M Pixel camera sensor with ISP + * Register map for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. * Author: HeungJun Kim <riverful.kim@samsung.com> @@ -16,104 +16,258 @@ #ifndef M5MOLS_REG_H #define M5MOLS_REG_H +#define M5MOLS_I2C_MAX_SIZE 4 +#define M5MOLS_BYTE_READ 0x01 +#define M5MOLS_BYTE_WRITE 0x02 + +#define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff) +#define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff) +#define I2C_SIZE(__reg_s) ((__reg_s) & 0xff) +#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s) + /* * Category section register * - * The category means a kind of command set. Including category section, - * all defined categories in this version supports only, as you see below: + * The category means set including relevant command of M-5MOLS. */ #define CAT_SYSTEM 0x00 #define CAT_PARAM 0x01 -#define CAT_MON 0x02 +#define CAT_MONITOR 0x02 #define CAT_AE 0x03 #define CAT_WB 0x06 #define CAT_EXIF 0x07 +#define CAT_FD 0x09 #define CAT_LENS 0x0a -#define CAT_CAPTURE_PARAMETER 0x0b -#define CAT_CAPTURE_CONTROL 0x0c -#define CAT_FLASH 0x0f /* related with FW, Verions, booting */ +#define CAT_CAPT_PARM 0x0b +#define CAT_CAPT_CTRL 0x0c +#define CAT_FLASH 0x0f /* related to FW, revisions, booting */ /* - * Category 0 - System + * Category 0 - SYSTEM mode + * + * The SYSTEM mode in the M-5MOLS means area available to handle with the whole + * & all-round system of sensor. It deals with version/interrupt/setting mode & + * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by + * packaging & manufacturer, even the customer and project code. And the + * function details may vary among them. The version information helps to + * determine what methods shall be used in the driver. * - * This category supports FW version, managing mode, even interrupt. + * There is many registers between customer version address and awb one. For + * more specific contents, see definition if file m5mols.h. */ -#define CAT0_CUSTOMER_CODE 0x00 -#define CAT0_PJ_CODE 0x01 -#define CAT0_VERSION_FW_H 0x02 -#define CAT0_VERSION_FW_L 0x03 -#define CAT0_VERSION_HW_H 0x04 -#define CAT0_VERSION_HW_L 0x05 -#define CAT0_VERSION_PARM_H 0x06 -#define CAT0_VERSION_PARM_L 0x07 -#define CAT0_VERSION_AWB_H 0x08 -#define CAT0_VERSION_AWB_L 0x09 -#define CAT0_SYSMODE 0x0b -#define CAT0_STATUS 0x0c -#define CAT0_INT_QUEUE 0x0e -#define CAT0_INT_FACTOR 0x10 /* ver 10bit: 0x10, other 0x1c */ -#define CAT0_INT_ENABLE 0x11 /* ver 10bit: 0x11, other 0x10 */ -#define CAT0_INT_ROOTEN 0x12 -#define CAT0_INT_INFO 0x18 +#define CAT0_VER_CUSTOMER 0x00 /* customer version */ +#define CAT0_VER_PROJECT 0x01 /* project version */ +#define CAT0_VER_FIRMWARE 0x02 /* Firmware version */ +#define CAT0_VER_HARDWARE 0x04 /* Hardware version */ +#define CAT0_VER_PARAMETER 0x06 /* Parameter version */ +#define CAT0_VER_AWB 0x08 /* Auto WB version */ +#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ +#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ +#define CAT0_STATUS 0x0c /* SYSTEM mode status register */ +#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ +#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ + +#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1) +#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1) +#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2) +#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2) +#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2) +#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2) + +#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) +#define REG_SYSINIT 0x00 /* SYSTEM mode */ +#define REG_PARAMETER 0x01 /* PARAMETER mode */ +#define REG_MONITOR 0x02 /* MONITOR mode */ +#define REG_CAPTURE 0x03 /* CAPTURE mode */ + +#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) +#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1) +#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ +#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ +#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ + +#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1) +#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1) +#define REG_INT_MODE (1 << 0) +#define REG_INT_AF (1 << 1) +#define REG_INT_ZOOM (1 << 2) +#define REG_INT_CAPTURE (1 << 3) +#define REG_INT_FRAMESYNC (1 << 4) +#define REG_INT_FD (1 << 5) +#define REG_INT_LENS_INIT (1 << 6) +#define REG_INT_SOUND (1 << 7) +#define REG_INT_MASK 0x0f /* - * category 1 - Parameter mode + * category 1 - PARAMETER mode * - * This category is dealing with almost camera vendor. In spite of that, - * It's a register to be able to detailed value for whole camera syste. - * The key parameter like a resolution, FPS, data interface connecting - * with Mobile AP, even effects. + * This category supports function of camera features of M-5MOLS. It means we + * can handle with preview(MONITOR) resolution size/frame per second/interface + * between the sensor and the Application Processor/even the image effect. */ -#define CAT1_DATA_INTERFACE 0x00 -#define CAT1_MONITOR_SIZE 0x01 -#define CAT1_MONITOR_FPS 0x02 -#define CAT1_EFFECT 0x0b +#define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */ +#define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */ +#define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */ +#define CAT1_EFFECT 0x0b /* image effects */ + +#define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1) + +#define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1) +#define REG_FPS_30 0x02 + +#define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1) +#define REG_INTERFACE_MIPI 0x02 + +#define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1) +#define REG_EFFECT_OFF 0x00 +#define REG_EFFECT_NEGA 0x01 +#define REG_EFFECT_EMBOSS 0x06 +#define REG_EFFECT_OUTLINE 0x07 +#define REG_EFFECT_WATERCOLOR 0x08 /* - * Category 2 - Monitor mode + * Category 2 - MONITOR mode * - * This category supports only monitoring mode. The monitoring mode means, - * similar to preview. It supports like a YUYV format. At the capture mode, - * it is handled like a JPEG & RAW formats. + * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another + * mode named "Preview", but this preview mode is used at the case specific + * vider-recording mode. This mmode supports only YUYV format. On the other + * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are + * another options like zoom/color effect(different with effect in PARAMETER + * mode)/anti hand shaking algorithm. */ -#define CAT2_ZOOM 0x01 -#define CAT2_ZOOM_POSITION 0x02 -#define CAT2_ZOOM_STEP 0x03 -#define CAT2_CFIXB 0x09 -#define CAT2_CFIXR 0x0a -#define CAT2_COLOR_EFFECT 0x0b -#define CAT2_CHROMA_LVL 0x0f -#define CAT2_CHROMA_EN 0x10 +#define CAT2_ZOOM 0x01 /* set the zoom position & execute */ +#define CAT2_ZOOM_STEP 0x03 /* set the zoom step */ +#define CAT2_CFIXB 0x09 /* CB value for color effect */ +#define CAT2_CFIXR 0x0a /* CR value for color effect */ +#define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */ +#define CAT2_CHROMA_LVL 0x0f /* set chroma level */ +#define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */ +#define CAT2_EDGE_LVL 0x11 /* set sharpness level */ +#define CAT2_EDGE_EN 0x12 /* set on/off sharpness */ +#define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */ + +#define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1) + +#define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1) +#define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1) +#define REG_CFIXB_SEPIA 0xd8 +#define REG_CFIXR_SEPIA 0x18 + +#define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1) +#define REG_COLOR_EFFECT_OFF 0x00 +#define REG_COLOR_EFFECT_ON 0x01 + +#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1) +#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1) +#define REG_CHROMA_OFF 0x00 +#define REG_CHROMA_ON 0x01 + +#define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1) +#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1) +#define REG_EDGE_OFF 0x00 +#define REG_EDGE_ON 0x01 + +#define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1) /* * Category 3 - Auto Exposure * - * Currently, it supports only gain value with monitor mode. This device - * is able to support Shutter, Gain(similar with Aperture), Flicker, at - * monitor mode & capture mode both. + * The M-5MOLS exposure capbility is detailed as which is similar to digital + * camera. This category supports AE locking/various AE mode(range of exposure) + * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the + * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be + * different. So, this category also provide getting the max/min values. And, + * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. */ -#define CAT3_AE_LOCK 0x00 -#define CAT3_AE_MODE 0x01 -#define CAT3_MANUAL_GAIN_MON 0x12 /* 2 bytes operations belows */ -#define CAT3_MANUAL_SHUT_MON 0x14 -#define CAT3_MAX_EXPOSURE_MON 0x16 -#define CAT3_MAX_EXPOSURE_CAP 0x18 -#define CAT3_MAX_GAIN_MON 0x1a -#define CAT3_MAX_GAIN_CAP 0x1c -#define CAT3_MANUAL_GAIN_CAP 0x26 -#define CAT3_MANUAL_SHUT_CAP 0x28 +#define CAT3_AE_LOCK 0x00 /* locking Auto exposure */ +#define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */ +#define CAT3_ISO 0x05 /* set ISO */ +#define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */ +#define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */ +#define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */ +#define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */ +#define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */ +#define CAT3_AE_INDEX 0x38 /* AE index */ + +#define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1) +#define REG_AE_UNLOCK 0x00 +#define REG_AE_LOCK 0x01 + +#define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1) +#define REG_AE_OFF 0x00 /* AE off */ +#define REG_AE_ALL 0x01 /* calc AE in all block integral */ +#define REG_AE_CENTER 0x03 /* calc AE in center weighted */ +#define REG_AE_SPOT 0x06 /* calc AE in specific spot */ + +#define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1) +#define REG_ISO_AUTO 0x00 +#define REG_ISO_50 0x01 +#define REG_ISO_100 0x02 +#define REG_ISO_200 0x03 +#define REG_ISO_400 0x04 +#define REG_ISO_800 0x05 + +#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1) +#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1) +#define REG_SCENE_NORMAL 0x00 +#define REG_SCENE_PORTRAIT 0x01 +#define REG_SCENE_LANDSCAPE 0x02 +#define REG_SCENE_SPORTS 0x03 +#define REG_SCENE_PARTY_INDOOR 0x04 +#define REG_SCENE_BEACH_SNOW 0x05 +#define REG_SCENE_SUNSET 0x06 +#define REG_SCENE_DAWN_DUSK 0x07 +#define REG_SCENE_FALL 0x08 +#define REG_SCENE_NIGHT 0x09 +#define REG_SCENE_AGAINST_LIGHT 0x0a +#define REG_SCENE_FIRE 0x0b +#define REG_SCENE_TEXT 0x0c +#define REG_SCENE_CANDLE 0x0d + +#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2) +#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2) +#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2) + +#define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1) +#define REG_AE_INDEX_20_NEG 0x00 +#define REG_AE_INDEX_15_NEG 0x01 +#define REG_AE_INDEX_10_NEG 0x02 +#define REG_AE_INDEX_05_NEG 0x03 +#define REG_AE_INDEX_00 0x04 +#define REG_AE_INDEX_05_POS 0x05 +#define REG_AE_INDEX_10_POS 0x06 +#define REG_AE_INDEX_15_POS 0x07 +#define REG_AE_INDEX_20_POS 0x08 /* * Category 6 - White Balance * - * Currently, it supports only auto white balance. + * This category provide AWB locking/mode/preset/speed/gain bias, etc. */ -#define CAT6_AWB_LOCK 0x00 -#define CAT6_AWB_MODE 0x02 -#define CAT6_AWB_MANUAL 0x03 +#define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */ +#define CAT6_AWB_MODE 0x02 /* set Auto or Manual */ +#define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */ + +#define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1) +#define REG_AWB_UNLOCK 0x00 +#define REG_AWB_LOCK 0x01 + +#define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1) +#define REG_AWB_AUTO 0x01 /* AWB off */ +#define REG_AWB_PRESET 0x02 /* AWB preset */ + +#define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1) +#define REG_AWB_INCANDESCENT 0x01 +#define REG_AWB_FLUORESCENT_1 0x02 +#define REG_AWB_FLUORESCENT_2 0x03 +#define REG_AWB_DAYLIGHT 0x04 +#define REG_AWB_CLOUDY 0x05 +#define REG_AWB_SHADE 0x06 +#define REG_AWB_HORIZON 0x07 +#define REG_AWB_LEDLIGHT 0x09 /* - * Category 7 - EXIF Information + * Category 7 - EXIF information */ #define CAT7_INFO_EXPTIME_NU 0x00 #define CAT7_INFO_EXPTIME_DE 0x04 @@ -130,35 +284,127 @@ #define CAT7_INFO_SDR 0x2c #define CAT7_INFO_QVAL 0x2e +#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4) +#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4) +#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4) +#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4) +#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4) +#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4) +#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4) +#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4) +#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4) +#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4) +#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2) +#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2) +#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2) +#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2) + +/* + * Category 9 - Face Detection + */ +#define CAT9_FD_CTL 0x00 + +#define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1) +#define BIT_FD_EN 0 +#define BIT_FD_DRAW_FACE_FRAME 4 +#define BIT_FD_DRAW_SMILE_LVL 6 +#define REG_FD(shift) (1 << shift) +#define REG_FD_OFF 0x0 + /* * Category A - Lens Parameter */ -#define CATA_INIT_AF_FUNC 0x00 #define CATA_AF_MODE 0x01 -#define CATA_AF_EXCUTE 0x02 +#define CATA_AF_EXECUTE 0x02 #define CATA_AF_STATUS 0x03 #define CATA_AF_VERSION 0x0a +#define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1) +#define REG_AF_NORMAL 0x00 /* Normal AF, one time */ +#define REG_AF_MACRO 0x01 /* Macro AF, one time */ +#define REG_AF_POWEROFF 0x07 + +#define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1) +#define REG_AF_STOP 0x00 +#define REG_AF_EXE_AUTO 0x01 +#define REG_AF_EXE_CAF 0x02 + +#define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1) +#define REG_AF_FAIL 0x00 +#define REG_AF_SUCCESS 0x02 +#define REG_AF_IDLE 0x04 +#define REG_AF_BUSY 0x05 + +#define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1) + /* - * Category B - Capture Parameter + * Category B - CAPTURE Parameter */ #define CATB_YUVOUT_MAIN 0x00 #define CATB_MAIN_IMAGE_SIZE 0x01 +#define CATB_MCC_MODE 0x1d +#define CATB_WDR_EN 0x2c +#define CATB_LIGHT_CTRL 0x40 +#define CATB_FLASH_CTRL 0x41 + +#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1) +#define REG_YUV422 0x00 +#define REG_BAYER10 0x05 +#define REG_BAYER8 0x06 +#define REG_JPEG 0x10 + +#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1) + +#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1) +#define REG_MCC_OFF 0x00 +#define REG_MCC_NORMAL 0x01 + +#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1) +#define REG_WDR_OFF 0x00 +#define REG_WDR_ON 0x01 +#define REG_WDR_AUTO 0x02 + +#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1) +#define REG_LIGHT_OFF 0x00 +#define REG_LIGHT_ON 0x01 +#define REG_LIGHT_AUTO 0x02 + +#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1) +#define REG_FLASH_OFF 0x00 +#define REG_FLASH_ON 0x01 +#define REG_FLASH_AUTO 0x02 /* - * Category C - Capture Control + * Category C - CAPTURE Control */ -#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi. */ +#define CATC_CAP_MODE 0x00 +#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */ #define CATC_CAP_START 0x09 #define CATC_CAP_IMAGE_SIZE 0x0d #define CATC_CAP_THUMB_SIZE 0x11 +#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1) +#define REG_CAP_NONE 0x00 +#define REG_CAP_ANTI_SHAKE 0x02 + +#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1) + +#define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1) +#define REG_CAP_START_MAIN 0x01 +#define REG_CAP_START_THUMB 0x03 + +#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4) +#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4) + /* * Category F - Flash * - * This mode provides functions about internal Flash works and System startup. + * This mode provides functions about internal flash stuff and system startup. */ -#define CATC_CAM_START 0x12 /* It start internal ARM core booting +#define CATF_CAM_START 0x12 /* It starts internal ARM core booting * after power-up */ +#define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1) +#define REG_START_ARM_BOOT 0x01 + #endif /* M5MOLS_REG_H */ diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig index e63233fd..390ab09 100644 --- a/drivers/media/video/omap/Kconfig +++ b/drivers/media/video/omap/Kconfig @@ -1,11 +1,14 @@ +config VIDEO_OMAP2_VOUT_VRFB + bool + config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" depends on ARCH_OMAP2 || ARCH_OMAP3 select VIDEOBUF_GEN select VIDEOBUF_DMA_CONTIG select OMAP2_DSS - select OMAP2_VRAM - select OMAP2_VRFB + select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 + select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB default n ---help--- V4L2 Display driver support for OMAP2/3 based boards. diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile index b287880..fc410b4 100644 --- a/drivers/media/video/omap/Makefile +++ b/drivers/media/video/omap/Makefile @@ -4,4 +4,5 @@ # OMAP2/3 Display driver omap-vout-y := omap_vout.o omap_voutlib.o +omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 4d07c58..d345215 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -35,9 +35,9 @@ #include <linux/sched.h> #include <linux/types.h> #include <linux/platform_device.h> -#include <linux/dma-mapping.h> #include <linux/irq.h> #include <linux/videodev2.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <media/videobuf-dma-contig.h> @@ -45,18 +45,17 @@ #include <media/v4l2-ioctl.h> #include <plat/dma.h> -#include <plat/vram.h> #include <plat/vrfb.h> #include <video/omapdss.h> #include "omap_voutlib.h" #include "omap_voutdef.h" +#include "omap_vout_vrfb.h" MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("OMAP Video for Linux Video out driver"); MODULE_LICENSE("GPL"); - /* Driver Configuration macros */ #define VOUT_NAME "omap_vout" @@ -65,31 +64,6 @@ enum omap_vout_channels { OMAP_VIDEO2, }; -enum dma_channel_state { - DMA_CHAN_NOT_ALLOTED, - DMA_CHAN_ALLOTED, -}; - -#define QQVGA_WIDTH 160 -#define QQVGA_HEIGHT 120 - -/* Max Resolution supported by the driver */ -#define VID_MAX_WIDTH 1280 /* Largest width */ -#define VID_MAX_HEIGHT 720 /* Largest height */ - -/* Mimimum requirement is 2x2 for DSS */ -#define VID_MIN_WIDTH 2 -#define VID_MIN_HEIGHT 2 - -/* 2048 x 2048 is max res supported by OMAP display controller */ -#define MAX_PIXELS_PER_LINE 2048 - -#define VRFB_TX_TIMEOUT 1000 -#define VRFB_NUM_BUFS 4 - -/* Max buffer size tobe allocated during init */ -#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4) - static struct videobuf_queue_ops video_vbq_ops; /* Variables configurable through module params*/ static u32 video1_numbuffers = 3; @@ -129,7 +103,7 @@ module_param(debug, bool, S_IRUGO); MODULE_PARM_DESC(debug, "Debug level (0-1)"); /* list of image formats supported by OMAP2 video pipelines */ -const static struct v4l2_fmtdesc omap_formats[] = { +static const struct v4l2_fmtdesc omap_formats[] = { { /* Note: V4L2 defines RGB565 as: * @@ -172,84 +146,6 @@ const static struct v4l2_fmtdesc omap_formats[] = { #define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats)) /* - * Allocate buffers - */ -static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr) -{ - u32 order, size; - unsigned long virt_addr, addr; - - size = PAGE_ALIGN(buf_size); - order = get_order(size); - virt_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, order); - addr = virt_addr; - - if (virt_addr) { - while (size > 0) { - SetPageReserved(virt_to_page(addr)); - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - *phys_addr = (u32) virt_to_phys((void *) virt_addr); - return virt_addr; -} - -/* - * Free buffers - */ -static void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size) -{ - u32 order, size; - unsigned long addr = virtaddr; - - size = PAGE_ALIGN(buf_size); - order = get_order(size); - - while (size > 0) { - ClearPageReserved(virt_to_page(addr)); - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - free_pages((unsigned long) virtaddr, order); -} - -/* - * Function for allocating video buffers - */ -static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout, - unsigned int *count, int startindex) -{ - int i, j; - - for (i = 0; i < *count; i++) { - if (!vout->smsshado_virt_addr[i]) { - vout->smsshado_virt_addr[i] = - omap_vout_alloc_buffer(vout->smsshado_size, - &vout->smsshado_phy_addr[i]); - } - if (!vout->smsshado_virt_addr[i] && startindex != -1) { - if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex) - break; - } - if (!vout->smsshado_virt_addr[i]) { - for (j = 0; j < i; j++) { - omap_vout_free_buffer( - vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; - } - *count = 0; - return -ENOMEM; - } - memset((void *) vout->smsshado_virt_addr[i], 0, - vout->smsshado_size); - } - return 0; -} - -/* * Try format */ static int omap_vout_try_format(struct v4l2_pix_format *pix) @@ -310,19 +206,21 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp) struct vm_area_struct *vma; struct mm_struct *mm = current->mm; - vma = find_vma(mm, virtp); /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) { - physp = virt_to_phys((void *) virtp); - } else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) { + if (virtp >= PAGE_OFFSET) + return virt_to_phys((void *) virtp); + + down_read(¤t->mm->mmap_sem); + vma = find_vma(mm, virtp); + if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) { /* this will catch, kernel-allocated, mmaped-to-usermode addresses */ physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); + up_read(¤t->mm->mmap_sem); } else { /* otherwise, use get_user_pages() for general userland pages */ int res, nr_pages = 1; struct page *pages; - down_read(¤t->mm->mmap_sem); res = get_user_pages(current, current->mm, virtp, nr_pages, 1, 0, &pages, NULL); @@ -342,73 +240,9 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp) } /* - * Wakes up the application once the DMA transfer to VRFB space is completed. - */ -static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data) -{ - struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data; - - t->tx_status = 1; - wake_up_interruptible(&t->wait); -} - -/* - * Release the VRFB context once the module exits - */ -static void omap_vout_release_vrfb(struct omap_vout_device *vout) -{ - int i; - - for (i = 0; i < VRFB_NUM_BUFS; i++) - omap_vrfb_release_ctx(&vout->vrfb_context[i]); - - if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) { - vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; - omap_free_dma(vout->vrfb_dma_tx.dma_ch); - } -} - -/* - * Return true if rotation is 90 or 270 - */ -static inline int rotate_90_or_270(const struct omap_vout_device *vout) -{ - return (vout->rotation == dss_rotation_90_degree || - vout->rotation == dss_rotation_270_degree); -} - -/* - * Return true if rotation is enabled - */ -static inline int rotation_enabled(const struct omap_vout_device *vout) -{ - return vout->rotation || vout->mirror; -} - -/* - * Reverse the rotation degree if mirroring is enabled - */ -static inline int calc_rotation(const struct omap_vout_device *vout) -{ - if (!vout->mirror) - return vout->rotation; - - switch (vout->rotation) { - case dss_rotation_90_degree: - return dss_rotation_270_degree; - case dss_rotation_270_degree: - return dss_rotation_90_degree; - case dss_rotation_180_degree: - return dss_rotation_0_degree; - default: - return dss_rotation_180_degree; - } -} - -/* * Free the V4L2 buffers */ -static void omap_vout_free_buffers(struct omap_vout_device *vout) +void omap_vout_free_buffers(struct omap_vout_device *vout) { int i, numbuffers; @@ -425,52 +259,6 @@ static void omap_vout_free_buffers(struct omap_vout_device *vout) } /* - * Free VRFB buffers - */ -static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) -{ - int j; - - for (j = 0; j < VRFB_NUM_BUFS; j++) { - omap_vout_free_buffer(vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; - } -} - -/* - * Allocate the buffers for the VRFB space. Data is copied from V4L2 - * buffers to the VRFB buffers using the DMA engine. - */ -static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, - unsigned int *count, unsigned int startindex) -{ - int i; - bool yuv_mode; - - /* Allocate the VRFB buffers only if the buffers are not - * allocated during init time. - */ - if ((rotation_enabled(vout)) && !vout->vrfb_static_allocation) - if (omap_vout_allocate_vrfb_buffers(vout, count, startindex)) - return -ENOMEM; - - if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 || - vout->dss_mode == OMAP_DSS_COLOR_UYVY) - yuv_mode = true; - else - yuv_mode = false; - - for (i = 0; i < *count; i++) - omap_vrfb_setup(&vout->vrfb_context[i], - vout->smsshado_phy_addr[i], vout->pix.width, - vout->pix.height, vout->bpp, yuv_mode); - - return 0; -} - -/* * Convert V4L2 rotation to DSS rotation * V4L2 understand 0, 90, 180, 270. * Convert to 0, 1, 2 and 3 respectively for DSS @@ -499,124 +287,38 @@ static int v4l2_rot_to_dss_rot(int v4l2_rotation, return ret; } -/* - * Calculate the buffer offsets from which the streaming should - * start. This offset calculation is mainly required because of - * the VRFB 32 pixels alignment with rotation. - */ static int omap_vout_calculate_offset(struct omap_vout_device *vout) { - struct omap_overlay *ovl; - enum dss_rotation rotation; struct omapvideo_info *ovid; - bool mirroring = vout->mirror; - struct omap_dss_device *cur_display; struct v4l2_rect *crop = &vout->crop; struct v4l2_pix_format *pix = &vout->pix; int *cropped_offset = &vout->cropped_offset; - int vr_ps = 1, ps = 2, temp_ps = 2; - int offset = 0, ctop = 0, cleft = 0, line_length = 0; + int ps = 2, line_length = 0; ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) - return -1; - cur_display = ovl->manager->device; - rotation = calc_rotation(vout); + if (ovid->rotation_type == VOUT_ROT_VRFB) { + omap_vout_calculate_vrfb_offset(vout); + } else { + vout->line_length = line_length = pix->width; - if (V4L2_PIX_FMT_YUYV == pix->pixelformat || - V4L2_PIX_FMT_UYVY == pix->pixelformat) { - if (rotation_enabled(vout)) { - /* - * ps - Actual pixel size for YUYV/UYVY for - * VRFB/Mirroring is 4 bytes - * vr_ps - Virtually pixel size for YUYV/UYVY is - * 2 bytes - */ + if (V4L2_PIX_FMT_YUYV == pix->pixelformat || + V4L2_PIX_FMT_UYVY == pix->pixelformat) + ps = 2; + else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) ps = 4; - vr_ps = 2; - } else { - ps = 2; /* otherwise the pixel size is 2 byte */ - } - } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) { - ps = 4; - } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) { - ps = 3; - } - vout->ps = ps; - vout->vr_ps = vr_ps; - - if (rotation_enabled(vout)) { - line_length = MAX_PIXELS_PER_LINE; - ctop = (pix->height - crop->height) - crop->top; - cleft = (pix->width - crop->width) - crop->left; - } else { - line_length = pix->width; - } - vout->line_length = line_length; - switch (rotation) { - case dss_rotation_90_degree: - offset = vout->vrfb_context[0].yoffset * - vout->vrfb_context[0].bytespp; - temp_ps = ps / vr_ps; - if (mirroring == 0) { - *cropped_offset = offset + line_length * - temp_ps * cleft + crop->top * temp_ps; - } else { - *cropped_offset = offset + line_length * temp_ps * - cleft + crop->top * temp_ps + (line_length * - ((crop->width / (vr_ps)) - 1) * ps); - } - break; - case dss_rotation_180_degree: - offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset * - vout->vrfb_context[0].bytespp) + - (vout->vrfb_context[0].xoffset * - vout->vrfb_context[0].bytespp)); - if (mirroring == 0) { - *cropped_offset = offset + (line_length * ps * ctop) + - (cleft / vr_ps) * ps; + else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) + ps = 3; - } else { - *cropped_offset = offset + (line_length * ps * ctop) + - (cleft / vr_ps) * ps + (line_length * - (crop->height - 1) * ps); - } - break; - case dss_rotation_270_degree: - offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset * - vout->vrfb_context[0].bytespp; - temp_ps = ps / vr_ps; - if (mirroring == 0) { - *cropped_offset = offset + line_length * - temp_ps * crop->left + ctop * ps; - } else { - *cropped_offset = offset + line_length * - temp_ps * crop->left + ctop * ps + - (line_length * ((crop->width / vr_ps) - 1) * - ps); - } - break; - case dss_rotation_0_degree: - if (mirroring == 0) { - *cropped_offset = (line_length * ps) * - crop->top + (crop->left / vr_ps) * ps; - } else { - *cropped_offset = (line_length * ps) * - crop->top + (crop->left / vr_ps) * ps + - (line_length * (crop->height - 1) * ps); - } - break; - default: - *cropped_offset = (line_length * ps * crop->top) / - vr_ps + (crop->left * ps) / vr_ps + - ((crop->width / vr_ps) - 1) * ps; - break; + vout->ps = ps; + + *cropped_offset = (line_length * ps) * + crop->top + crop->left * ps; } + v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n", - __func__, *cropped_offset); + __func__, vout->cropped_offset); + return 0; } @@ -664,7 +366,7 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout) /* * Setup the overlay */ -int omapvid_setup_overlay(struct omap_vout_device *vout, +static int omapvid_setup_overlay(struct omap_vout_device *vout, struct omap_overlay *ovl, int posx, int posy, int outw, int outh, u32 addr) { @@ -687,7 +389,7 @@ int omapvid_setup_overlay(struct omap_vout_device *vout, /* Setup the input plane parameters according to * rotation value selected. */ - if (rotate_90_or_270(vout)) { + if (is_rotation_90_or_270(vout)) { cropheight = vout->crop.width; cropwidth = vout->crop.height; pixheight = vout->pix.width; @@ -701,7 +403,6 @@ int omapvid_setup_overlay(struct omap_vout_device *vout, ovl->get_overlay_info(ovl, &info); info.paddr = addr; - info.vaddr = NULL; info.width = cropwidth; info.height = cropheight; info.color_mode = vout->dss_mode; @@ -711,7 +412,7 @@ int omapvid_setup_overlay(struct omap_vout_device *vout, info.out_width = outw; info.out_height = outh; info.global_alpha = vout->win.global_alpha; - if (!rotation_enabled(vout)) { + if (!is_rotation_enabled(vout)) { info.rotation = 0; info.rotation_type = OMAP_DSS_ROT_DMA; info.screen_width = pixwidth; @@ -744,7 +445,7 @@ setup_ovl_err: /* * Initialize the overlay structure */ -int omapvid_init(struct omap_vout_device *vout, u32 addr) +static int omapvid_init(struct omap_vout_device *vout, u32 addr) { int ret = 0, i; struct v4l2_window *win; @@ -809,7 +510,7 @@ omapvid_init_err: /* * Apply the changes set the go bit of DSS */ -int omapvid_apply_changes(struct omap_vout_device *vout) +static int omapvid_apply_changes(struct omap_vout_device *vout) { int i; struct omap_overlay *ovl; @@ -825,7 +526,7 @@ int omapvid_apply_changes(struct omap_vout_device *vout) return 0; } -void omap_vout_isr(void *arg, unsigned int irqstatus) +static void omap_vout_isr(void *arg, unsigned int irqstatus) { int ret; u32 addr, fid; @@ -848,10 +549,20 @@ void omap_vout_isr(void *arg, unsigned int irqstatus) spin_lock(&vout->vbq_lock); do_gettimeofday(&timevalue); - if (cur_display->type == OMAP_DISPLAY_TYPE_DPI) { - if (!(irqstatus & DISPC_IRQ_VSYNC)) - goto vout_isr_err; + if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) { + switch (cur_display->type) { + case OMAP_DISPLAY_TYPE_DPI: + if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2))) + goto vout_isr_err; + break; + case OMAP_DISPLAY_TYPE_HDMI: + if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN)) + goto vout_isr_err; + break; + default: + goto vout_isr_err; + } if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { vout->cur_frm->ts = timevalue; vout->cur_frm->state = VIDEOBUF_DONE; @@ -875,7 +586,7 @@ void omap_vout_isr(void *arg, unsigned int irqstatus) ret = omapvid_init(vout, addr); if (ret) printk(KERN_ERR VOUT_NAME - "failed to set overlay info\n"); + "failed to set overlay info\n"); /* Enable the pipeline and set the Go bit */ ret = omapvid_apply_changes(vout); if (ret) @@ -954,6 +665,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, int startindex = 0, i, j; u32 phy_addr = 0, virt_addr = 0; struct omap_vout_device *vout = q->priv_data; + struct omapvideo_info *ovid = &vout->vid_info; if (!vout) return -EINVAL; @@ -966,13 +678,10 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex) *count = startindex; - if ((rotation_enabled(vout)) && *count > VRFB_NUM_BUFS) - *count = VRFB_NUM_BUFS; - - /* If rotation is enabled, allocate memory for VRFB space also */ - if (rotation_enabled(vout)) + if (ovid->rotation_type == VOUT_ROT_VRFB) { if (omap_vout_vrfb_buffer_setup(vout, count, startindex)) return -ENOMEM; + } if (V4L2_MEMORY_MMAP != vout->memory) return 0; @@ -996,8 +705,11 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, virt_addr = omap_vout_alloc_buffer(vout->buffer_size, &phy_addr); if (!virt_addr) { - if (!rotation_enabled(vout)) + if (ovid->rotation_type == VOUT_ROT_NONE) { break; + } else { + if (!is_rotation_enabled(vout)) + break; /* Free the VRFB buffers if no space for V4L2 buffers */ for (j = i; j < *count; j++) { omap_vout_free_buffer( @@ -1005,6 +717,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, vout->smsshado_size); vout->smsshado_virt_addr[j] = 0; vout->smsshado_phy_addr[j] = 0; + } } } vout->buf_virt_addr[i] = virt_addr; @@ -1017,9 +730,9 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, /* * Free the V4L2 buffers additionally allocated than default - * number of buffers and free all the VRFB buffers + * number of buffers */ -static void omap_vout_free_allbuffers(struct omap_vout_device *vout) +static void omap_vout_free_extra_buffers(struct omap_vout_device *vout) { int num_buffers = 0, i; @@ -1034,20 +747,6 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout) vout->buf_virt_addr[i] = 0; vout->buf_phy_addr[i] = 0; } - /* Free the VRFB buffers only if they are allocated - * during reqbufs. Don't free if init time allocated - */ - if (!vout->vrfb_static_allocation) { - for (i = 0; i < VRFB_NUM_BUFS; i++) { - if (vout->smsshado_virt_addr[i]) { - omap_vout_free_buffer( - vout->smsshado_virt_addr[i], - vout->smsshado_size); - vout->smsshado_virt_addr[i] = 0; - vout->smsshado_phy_addr[i] = 0; - } - } - } vout->buffer_allocated = num_buffers; } @@ -1059,16 +758,11 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout) * buffer into VRFB memory space before giving it to the DSS. */ static int omap_vout_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) + struct videobuf_buffer *vb, + enum v4l2_field field) { - dma_addr_t dmabuf; - struct vid_vrfb_dma *tx; - enum dss_rotation rotation; struct omap_vout_device *vout = q->priv_data; - u32 dest_frame_index = 0, src_element_index = 0; - u32 dest_element_index = 0, src_frame_index = 0; - u32 elem_count = 0, frame_count = 0, pixsize = 2; + struct omapvideo_info *ovid = &vout->vid_info; if (VIDEOBUF_NEEDS_INIT == vb->state) { vb->width = vout->pix.width; @@ -1087,66 +781,24 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, vout->queued_buf_addr[vb->i] = (u8 *) omap_vout_uservirt_to_phys(vb->baddr); } else { - vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; - } + u32 addr, dma_addr; + unsigned long size; - if (!rotation_enabled(vout)) - return 0; + addr = (unsigned long) vout->buf_virt_addr[vb->i]; + size = (unsigned long) vb->size; - dmabuf = vout->buf_phy_addr[vb->i]; - /* If rotation is enabled, copy input buffer into VRFB - * memory space using DMA. We are copying input buffer - * into VRFB memory space of desired angle and DSS will - * read image VRFB memory for 0 degree angle - */ - pixsize = vout->bpp * vout->vrfb_bpp; - /* - * DMA transfer in double index mode - */ + dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr, + size, DMA_TO_DEVICE); + if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr)) + v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n"); - /* Frame index */ - dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) - - (vout->pix.width * vout->bpp)) + 1; - - /* Source and destination parameters */ - src_element_index = 0; - src_frame_index = 0; - dest_element_index = 1; - /* Number of elements per frame */ - elem_count = vout->pix.width * vout->bpp; - frame_count = vout->pix.height; - tx = &vout->vrfb_dma_tx; - tx->tx_status = 0; - omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32, - (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT, - tx->dev_id, 0x0); - /* src_port required only for OMAP1 */ - omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, - dmabuf, src_element_index, src_frame_index); - /*set dma source burst mode for VRFB */ - omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); - rotation = calc_rotation(vout); - - /* dest_port required only for OMAP1 */ - omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX, - vout->vrfb_context[vb->i].paddr[0], dest_element_index, - dest_frame_index); - /*set dma dest burst mode for VRFB */ - omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); - omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0); - - omap_start_dma(tx->dma_ch); - interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT); - - if (tx->tx_status == 0) { - omap_stop_dma(tx->dma_ch); - return -EINVAL; + vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; } - /* Store buffers physical address into an array. Addresses - * from this array will be used to configure DSS */ - vout->queued_buf_addr[vb->i] = (u8 *) - vout->vrfb_context[vb->i].paddr[rotation]; - return 0; + + if (ovid->rotation_type == VOUT_ROT_VRFB) + return omap_vout_prepare_vrfb(vout, vb); + else + return 0; } /* @@ -1184,6 +836,15 @@ static void omap_vout_buffer_release(struct videobuf_queue *q, /* * File operations */ +static unsigned int omap_vout_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct omap_vout_device *vout = file->private_data; + struct videobuf_queue *q = &vout->vbq; + + return videobuf_poll_stream(file, q, wait); +} + static void omap_vout_vm_open(struct vm_area_struct *vma) { struct omap_vout_device *vout = vma->vm_private_data; @@ -1298,7 +959,15 @@ static int omap_vout_release(struct file *file) "Unable to apply changes\n"); /* Free all buffers */ - omap_vout_free_allbuffers(vout); + omap_vout_free_extra_buffers(vout); + + /* Free the VRFB buffers only if they are allocated + * during reqbufs. Don't free if init time allocated + */ + if (ovid->rotation_type == VOUT_ROT_VRFB) { + if (!vout->vrfb_static_allocation) + omap_vout_free_vrfb_buffers(vout); + } videobuf_mmap_free(q); /* Even if apply changes fails we should continue @@ -1307,7 +976,7 @@ static int omap_vout_release(struct file *file) u32 mask = 0; mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | - DISPC_IRQ_EVSYNC_ODD; + DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; omap_dispc_unregister_isr(omap_vout_isr, vout, mask); vout->streaming = 0; @@ -1383,10 +1052,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { int index = fmt->index; - enum v4l2_buf_type type = fmt->type; - fmt->index = index; - fmt->type = type; if (index >= NUM_OUTPUT_FORMATS) return -EINVAL; @@ -1457,7 +1123,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, /* We dont support RGB24-packed mode if vrfb rotation * is enabled*/ - if ((rotation_enabled(vout)) && + if ((is_rotation_enabled(vout)) && f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { ret = -EINVAL; goto s_fmt_vid_out_exit; @@ -1465,7 +1131,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, /* get the framebuffer parameters */ - if (rotate_90_or_270(vout)) { + if (is_rotation_90_or_270(vout)) { vout->fbuf.fmt.height = timing->x_res; vout->fbuf.fmt.width = timing->y_res; } else { @@ -1510,12 +1176,17 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, { int ret = 0; struct omap_vout_device *vout = fh; + struct omap_overlay *ovl; + struct omapvideo_info *ovid; struct v4l2_window *win = &f->fmt.win; + ovid = &vout->vid_info; + ovl = ovid->overlays[0]; + ret = omap_vout_try_window(&vout->fbuf, win); if (!ret) { - if (vout->vid == OMAP_VIDEO1) + if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) win->global_alpha = 255; else win->global_alpha = f->fmt.win.global_alpha; @@ -1539,8 +1210,8 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh, ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win); if (!ret) { - /* Video1 plane does not support global alpha */ - if (ovl->id == OMAP_DSS_VIDEO1) + /* Video1 plane does not support global alpha on OMAP3 */ + if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) vout->win.global_alpha = 255; else vout->win.global_alpha = f->fmt.win.global_alpha; @@ -1555,10 +1226,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { int index = fmt->index; - enum v4l2_buf_type type = fmt->type; - fmt->index = index; - fmt->type = type; if (index >= NUM_OUTPUT_FORMATS) return -EINVAL; @@ -1645,7 +1313,7 @@ static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) /* get the display device attached to the overlay */ timing = &ovl->manager->device->panel.timings; - if (rotate_90_or_270(vout)) { + if (is_rotation_90_or_270(vout)) { vout->fbuf.fmt.height = timing->x_res; vout->fbuf.fmt.width = timing->y_res; } else { @@ -1725,9 +1393,17 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) switch (a->id) { case V4L2_CID_ROTATE: { + struct omapvideo_info *ovid; int rotation = a->value; + ovid = &vout->vid_info; + mutex_lock(&vout->lock); + if (rotation && ovid->rotation_type == VOUT_ROT_NONE) { + mutex_unlock(&vout->lock); + ret = -ERANGE; + break; + } if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { mutex_unlock(&vout->lock); @@ -1783,6 +1459,11 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) ovl = ovid->overlays[0]; mutex_lock(&vout->lock); + if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { + mutex_unlock(&vout->lock); + ret = -ERANGE; + break; + } if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { mutex_unlock(&vout->lock); @@ -1893,7 +1574,7 @@ static int vidioc_qbuf(struct file *file, void *fh, } } - if ((rotation_enabled(vout)) && + if ((is_rotation_enabled(vout)) && vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) { v4l2_warn(&vout->vid_dev->v4l2_dev, "DMA Channel not allocated for Rotation\n"); @@ -1908,15 +1589,28 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) struct omap_vout_device *vout = fh; struct videobuf_queue *q = &vout->vbq; + int ret; + u32 addr; + unsigned long size; + struct videobuf_buffer *vb; + + vb = q->bufs[b->index]; + if (!vout->streaming) return -EINVAL; if (file->f_flags & O_NONBLOCK) /* Call videobuf_dqbuf for non blocking mode */ - return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1); + ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1); else /* Call videobuf_dqbuf for blocking mode */ - return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0); + ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0); + + addr = (unsigned long) vout->buf_phy_addr[vb->i]; + size = (unsigned long) vb->size; + dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr, + size, DMA_TO_DEVICE); + return ret; } static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) @@ -1965,7 +1659,8 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i] + vout->cropped_offset; - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; + mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD + | DISPC_IRQ_VSYNC2; omap_dispc_register_isr(omap_vout_isr, vout, mask); @@ -2015,7 +1710,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) return -EINVAL; vout->streaming = 0; - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; + mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD + | DISPC_IRQ_VSYNC2; omap_dispc_unregister_isr(omap_vout_isr, vout, mask); @@ -2108,7 +1804,9 @@ static int vidioc_s_fbuf(struct file *file, void *fh, if (ovl->manager && ovl->manager->get_manager_info && ovl->manager->set_manager_info) { ovl->manager->get_manager_info(ovl->manager, &info); - info.alpha_enabled = enable; + /* enable this only if there is no zorder cap */ + if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + info.partial_alpha_enabled = enable; if (ovl->manager->set_manager_info(ovl->manager, &info)) return -EINVAL; } @@ -2140,7 +1838,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh, } if (ovl->manager && ovl->manager->get_manager_info) { ovl->manager->get_manager_info(ovl->manager, &info); - if (info.alpha_enabled) + if (info.partial_alpha_enabled) a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; } @@ -2175,6 +1873,7 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { static const struct v4l2_file_operations omap_vout_fops = { .owner = THIS_MODULE, + .poll = omap_vout_poll, .unlocked_ioctl = video_ioctl2, .mmap = omap_vout_mmap, .open = omap_vout_open, @@ -2228,7 +1927,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) vout->mirror = 0; vout->control[2].id = V4L2_CID_HFLIP; vout->control[2].value = 0; - vout->vrfb_bpp = 2; + if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) + vout->vrfb_bpp = 2; control[1].id = V4L2_CID_BG_COLOR; control[1].value = 0; @@ -2260,17 +1960,15 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, int vid_num) { u32 numbuffers; - int ret = 0, i, j; - int image_width, image_height; - struct video_device *vfd; + int ret = 0, i; + struct omapvideo_info *ovid; struct omap_vout_device *vout; - int static_vrfb_allocation = 0, vrfb_num_bufs = VRFB_NUM_BUFS; struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct omap2video_device *vid_dev = container_of(v4l2_dev, struct omap2video_device, v4l2_dev); vout = vid_dev->vouts[vid_num]; - vfd = vout->vfd; + ovid = &vout->vid_info; numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers; vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize; @@ -2287,66 +1985,16 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, } } - for (i = 0; i < VRFB_NUM_BUFS; i++) { - if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) { - dev_info(&pdev->dev, ": VRFB allocation failed\n"); - for (j = 0; j < i; j++) - omap_vrfb_release_ctx(&vout->vrfb_context[j]); - ret = -ENOMEM; - goto free_buffers; - } - } vout->cropped_offset = 0; - /* Calculate VRFB memory size */ - /* allocate for worst case size */ - image_width = VID_MAX_WIDTH / TILE_SIZE; - if (VID_MAX_WIDTH % TILE_SIZE) - image_width++; - - image_width = image_width * TILE_SIZE; - image_height = VID_MAX_HEIGHT / TILE_SIZE; - - if (VID_MAX_HEIGHT % TILE_SIZE) - image_height++; - - image_height = image_height * TILE_SIZE; - vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2); - - /* - * Request and Initialize DMA, for DMA based VRFB transfer - */ - vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE; - vout->vrfb_dma_tx.dma_ch = -1; - vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED; - ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX", - omap_vout_vrfb_dma_tx_callback, - (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); - if (ret < 0) { - vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; - dev_info(&pdev->dev, ": failed to allocate DMA Channel for" - " video%d\n", vfd->minor); - } - init_waitqueue_head(&vout->vrfb_dma_tx.wait); - - /* Allocate VRFB buffers if selected through bootargs */ - static_vrfb_allocation = (vid_num == 0) ? - vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; - - /* statically allocated the VRFB buffer is done through - commands line aruments */ - if (static_vrfb_allocation) { - if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) { - ret = -ENOMEM; - goto release_vrfb_ctx; - } - vout->vrfb_static_allocation = 1; + if (ovid->rotation_type == VOUT_ROT_VRFB) { + int static_vrfb_allocation = (vid_num == 0) ? + vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; + ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, + static_vrfb_allocation); } - return 0; -release_vrfb_ctx: - for (j = 0; j < VRFB_NUM_BUFS; j++) - omap_vrfb_release_ctx(&vout->vrfb_context[j]); + return ret; free_buffers: for (i = 0; i < numbuffers; i++) { @@ -2389,6 +2037,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) vout->vid_info.num_overlays = 1; vout->vid_info.id = k + 1; + /* Set VRFB as rotation_type for omap2 and omap3 */ + if (cpu_is_omap24xx() || cpu_is_omap34xx()) + vout->vid_info.rotation_type = VOUT_ROT_VRFB; + /* Setup the default configuration for the video devices */ if (omap_vout_setup_video_data(vout) != 0) { @@ -2422,7 +2074,8 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) goto success; error2: - omap_vout_release_vrfb(vout); + if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) + omap_vout_release_vrfb(vout); omap_vout_free_buffers(vout); error1: video_device_release(vfd); @@ -2443,11 +2096,13 @@ success: static void omap_vout_cleanup_device(struct omap_vout_device *vout) { struct video_device *vfd; + struct omapvideo_info *ovid; if (!vout) return; vfd = vout->vfd; + ovid = &vout->vid_info; if (vfd) { if (!video_is_registered(vfd)) { /* @@ -2463,14 +2118,15 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout) video_unregister_device(vfd); } } - - omap_vout_release_vrfb(vout); + if (ovid->rotation_type == VOUT_ROT_VRFB) { + omap_vout_release_vrfb(vout); + /* Free the VRFB buffer if allocated + * init time + */ + if (vout->vrfb_static_allocation) + omap_vout_free_vrfb_buffers(vout); + } omap_vout_free_buffers(vout); - /* Free the VRFB buffer if allocated - * init time - */ - if (vout->vrfb_static_allocation) - omap_vout_free_vrfb_buffers(vout); kfree(vout); } @@ -2516,6 +2172,14 @@ static int __init omap_vout_probe(struct platform_device *pdev) vid_dev->num_displays = 0; for_each_dss_dev(dssdev) { omap_dss_get_device(dssdev); + + if (!dssdev->driver) { + dev_warn(&pdev->dev, "no driver for display: %s\n", + dssdev->name); + omap_dss_put_device(dssdev); + continue; + } + vid_dev->displays[vid_dev->num_displays++] = dssdev; } @@ -2557,19 +2221,6 @@ static int __init omap_vout_probe(struct platform_device *pdev) "'%s' Display already enabled\n", def_display->name); } - /* set the update mode */ - if (def_display->caps & - OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - if (dssdrv->enable_te) - dssdrv->enable_te(def_display, 0); - if (dssdrv->set_update_mode) - dssdrv->set_update_mode(def_display, - OMAP_DSS_UPDATE_MANUAL); - } else { - if (dssdrv->set_update_mode) - dssdrv->set_update_mode(def_display, - OMAP_DSS_UPDATE_AUTO); - } } } diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h index 659497b..d793501 100644 --- a/drivers/media/video/omap/omap_voutdef.h +++ b/drivers/media/video/omap/omap_voutdef.h @@ -12,6 +12,7 @@ #define OMAP_VOUTDEF_H #include <video/omapdss.h> +#include <plat/vrfb.h> #define YUYV_BPP 2 #define RGB565_BPP 2 @@ -27,6 +28,31 @@ #define MAX_DISPLAYS 3 #define MAX_MANAGERS 3 +#define QQVGA_WIDTH 160 +#define QQVGA_HEIGHT 120 + +/* Max Resolution supported by the driver */ +#define VID_MAX_WIDTH 1280 /* Largest width */ +#define VID_MAX_HEIGHT 720 /* Largest height */ + +/* Mimimum requirement is 2x2 for DSS */ +#define VID_MIN_WIDTH 2 +#define VID_MIN_HEIGHT 2 + +/* 2048 x 2048 is max res supported by OMAP display controller */ +#define MAX_PIXELS_PER_LINE 2048 + +#define VRFB_TX_TIMEOUT 1000 +#define VRFB_NUM_BUFS 4 + +/* Max buffer size tobe allocated during init */ +#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4) + +enum dma_channel_state { + DMA_CHAN_NOT_ALLOTED, + DMA_CHAN_ALLOTED, +}; + /* Enum for Rotation * DSS understands rotation in 0, 1, 2, 3 context * while V4L2 driver understands it as 0, 90, 180, 270 @@ -37,6 +63,18 @@ enum dss_rotation { dss_rotation_180_degree = 2, dss_rotation_270_degree = 3, }; + +/* Enum for choosing rotation type for vout + * DSS2 doesn't understand no rotation as an + * option while V4L2 driver doesn't support + * rotation in the case where VRFB is not built in + * the kernel + */ +enum vout_rotaion_type { + VOUT_ROT_NONE = 0, + VOUT_ROT_VRFB = 1, +}; + /* * This structure is used to store the DMA transfer parameters * for VRFB hidden buffer @@ -53,6 +91,7 @@ struct omapvideo_info { int id; int num_overlays; struct omap_overlay *overlays[MAX_OVLS]; + enum vout_rotaion_type rotation_type; }; struct omap2video_device { @@ -144,4 +183,43 @@ struct omap_vout_device { int io_allowed; }; + +/* + * Return true if rotation is 90 or 270 + */ +static inline int is_rotation_90_or_270(const struct omap_vout_device *vout) +{ + return (vout->rotation == dss_rotation_90_degree || + vout->rotation == dss_rotation_270_degree); +} + +/* + * Return true if rotation is enabled + */ +static inline int is_rotation_enabled(const struct omap_vout_device *vout) +{ + return vout->rotation || vout->mirror; +} + +/* + * Reverse the rotation degree if mirroring is enabled + */ +static inline int calc_rotation(const struct omap_vout_device *vout) +{ + if (!vout->mirror) + return vout->rotation; + + switch (vout->rotation) { + case dss_rotation_90_degree: + return dss_rotation_270_degree; + case dss_rotation_270_degree: + return dss_rotation_90_degree; + case dss_rotation_180_degree: + return dss_rotation_0_degree; + default: + return dss_rotation_180_degree; + } +} + +void omap_vout_free_buffers(struct omap_vout_device *vout); #endif /* ifndef OMAP_VOUTDEF_H */ diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c index 8ae7481..115408b 100644 --- a/drivers/media/video/omap/omap_voutlib.c +++ b/drivers/media/video/omap/omap_voutlib.c @@ -24,8 +24,12 @@ #include <linux/types.h> #include <linux/videodev2.h> +#include <linux/dma-mapping.h> + #include <plat/cpu.h> +#include "omap_voutlib.h" + MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("OMAP Video library"); MODULE_LICENSE("GPL"); @@ -291,3 +295,45 @@ void omap_vout_new_format(struct v4l2_pix_format *pix, } EXPORT_SYMBOL_GPL(omap_vout_new_format); +/* + * Allocate buffers + */ +unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr) +{ + u32 order, size; + unsigned long virt_addr, addr; + + size = PAGE_ALIGN(buf_size); + order = get_order(size); + virt_addr = __get_free_pages(GFP_KERNEL, order); + addr = virt_addr; + + if (virt_addr) { + while (size > 0) { + SetPageReserved(virt_to_page(addr)); + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + *phys_addr = (u32) virt_to_phys((void *) virt_addr); + return virt_addr; +} + +/* + * Free buffers + */ +void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size) +{ + u32 order, size; + unsigned long addr = virtaddr; + + size = PAGE_ALIGN(buf_size); + order = get_order(size); + + while (size > 0) { + ClearPageReserved(virt_to_page(addr)); + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + free_pages((unsigned long) virtaddr, order); +} diff --git a/drivers/media/video/omap/omap_voutlib.h b/drivers/media/video/omap/omap_voutlib.h index a60b16e..e51750a 100644 --- a/drivers/media/video/omap/omap_voutlib.h +++ b/drivers/media/video/omap/omap_voutlib.h @@ -12,23 +12,25 @@ #ifndef OMAP_VOUTLIB_H #define OMAP_VOUTLIB_H -extern void omap_vout_default_crop(struct v4l2_pix_format *pix, +void omap_vout_default_crop(struct v4l2_pix_format *pix, struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop); -extern int omap_vout_new_crop(struct v4l2_pix_format *pix, +int omap_vout_new_crop(struct v4l2_pix_format *pix, struct v4l2_rect *crop, struct v4l2_window *win, struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop); -extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf, +int omap_vout_try_window(struct v4l2_framebuffer *fbuf, struct v4l2_window *new_win); -extern int omap_vout_new_window(struct v4l2_rect *crop, +int omap_vout_new_window(struct v4l2_rect *crop, struct v4l2_window *win, struct v4l2_framebuffer *fbuf, struct v4l2_window *new_win); -extern void omap_vout_new_format(struct v4l2_pix_format *pix, +void omap_vout_new_format(struct v4l2_pix_format *pix, struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop, struct v4l2_window *win); +unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr); +void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size); #endif /* #ifndef OMAP_VOUTLIB_H */ diff --git a/drivers/media/video/omap3isp/Makefile b/drivers/media/video/omap3isp/Makefile index b1b34477..e8847e7 100644 --- a/drivers/media/video/omap3isp/Makefile +++ b/drivers/media/video/omap3isp/Makefile @@ -1,8 +1,6 @@ # Makefile for OMAP3 ISP driver -ifdef CONFIG_VIDEO_OMAP3_DEBUG -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_VIDEO_OMAP3_DEBUG) += -DDEBUG omap3-isp-objs += \ isp.o ispqueue.o ispvideo.o \ diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 94b6ed8..b818cac 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -80,6 +80,13 @@ #include "isph3a.h" #include "isphist.h" +/* + * this is provided as an interim solution until omap3isp doesn't need + * any omap-specific iommu API + */ +#define to_iommu(dev) \ + (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev)) + static unsigned int autoidle; module_param(autoidle, int, 0444); MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support"); @@ -732,7 +739,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, struct media_pad *pad; struct v4l2_subdev *subdev; unsigned long flags; - int ret = 0; + int ret; spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT); @@ -756,7 +763,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, ret = v4l2_subdev_call(subdev, video, s_stream, mode); if (ret < 0 && ret != -ENOIOCTLCMD) - break; + return ret; if (subdev == &isp->isp_ccdc.subdev) { v4l2_subdev_call(&isp->isp_aewb.subdev, video, @@ -777,7 +784,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT) atomic_inc(&pipe->frame_number); - return ret; + return 0; } static int isp_pipeline_wait_resizer(struct isp_device *isp) @@ -1108,7 +1115,7 @@ static void isp_save_ctx(struct isp_device *isp) { isp_save_context(isp, isp_reg_list); if (isp->iommu) - iommu_save_ctx(isp->iommu); + omap_iommu_save_ctx(isp->iommu); } /* @@ -1122,7 +1129,7 @@ static void isp_restore_ctx(struct isp_device *isp) { isp_restore_context(isp, isp_reg_list); if (isp->iommu) - iommu_restore_ctx(isp->iommu); + omap_iommu_restore_ctx(isp->iommu); omap3isp_ccdc_restore_context(isp); omap3isp_preview_restore_context(isp); } @@ -1697,6 +1704,7 @@ static int isp_register_entities(struct isp_device *isp) isp->media_dev.dev = isp->dev; strlcpy(isp->media_dev.model, "TI OMAP3 ISP", sizeof(isp->media_dev.model)); + isp->media_dev.hw_revision = isp->revision; isp->media_dev.link_notify = isp_pipeline_link_notify; ret = media_device_register(&isp->media_dev); if (ret < 0) { @@ -1975,7 +1983,8 @@ static int isp_remove(struct platform_device *pdev) isp_cleanup_modules(isp); omap3isp_get(isp); - iommu_put(isp->iommu); + iommu_detach_device(isp->domain, isp->iommu_dev); + iommu_domain_free(isp->domain); omap3isp_put(isp); free_irq(isp->irq_num, isp); @@ -2123,25 +2132,41 @@ static int isp_probe(struct platform_device *pdev) } /* IOMMU */ - isp->iommu = iommu_get("isp"); - if (IS_ERR_OR_NULL(isp->iommu)) { - isp->iommu = NULL; + isp->iommu_dev = omap_find_iommu_device("isp"); + if (!isp->iommu_dev) { + dev_err(isp->dev, "omap_find_iommu_device failed\n"); ret = -ENODEV; goto error_isp; } + /* to be removed once iommu migration is complete */ + isp->iommu = to_iommu(isp->iommu_dev); + + isp->domain = iommu_domain_alloc(pdev->dev.bus); + if (!isp->domain) { + dev_err(isp->dev, "can't alloc iommu domain\n"); + ret = -ENOMEM; + goto error_isp; + } + + ret = iommu_attach_device(isp->domain, isp->iommu_dev); + if (ret) { + dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret); + goto free_domain; + } + /* Interrupt */ isp->irq_num = platform_get_irq(pdev, 0); if (isp->irq_num <= 0) { dev_err(isp->dev, "No IRQ resource\n"); ret = -ENODEV; - goto error_isp; + goto detach_dev; } if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) { dev_err(isp->dev, "Unable to request IRQ\n"); ret = -EINVAL; - goto error_isp; + goto detach_dev; } /* Entities */ @@ -2162,8 +2187,11 @@ error_modules: isp_cleanup_modules(isp); error_irq: free_irq(isp->irq_num, isp); +detach_dev: + iommu_detach_device(isp->domain, isp->iommu_dev); +free_domain: + iommu_domain_free(isp->domain); error_isp: - iommu_put(isp->iommu); omap3isp_put(isp); error: isp_put_clocks(isp); @@ -2183,6 +2211,8 @@ error: regulator_put(isp->isp_csiphy2.vdd); regulator_put(isp->isp_csiphy1.vdd); platform_set_drvdata(pdev, NULL); + + mutex_destroy(&isp->isp_mutex); kfree(isp); return ret; @@ -2234,3 +2264,4 @@ module_exit(isp_cleanup); MODULE_AUTHOR("Nokia Corporation"); MODULE_DESCRIPTION("TI OMAP3 ISP driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(ISP_VIDEO_DRIVER_VERSION); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index 2620c40..705946e 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -27,11 +27,13 @@ #ifndef OMAP3_ISP_CORE_H #define OMAP3_ISP_CORE_H +#include <media/omap3isp.h> #include <media/v4l2-device.h> #include <linux/device.h> #include <linux/io.h> #include <linux/platform_device.h> #include <linux/wait.h> +#include <linux/iommu.h> #include <plat/iommu.h> #include <plat/iovmm.h> @@ -94,14 +96,6 @@ enum isp_subclk_resource { OMAP3_ISP_SUBCLK_RESIZER = (1 << 4), }; -enum isp_interface_type { - ISP_INTERFACE_PARALLEL, - ISP_INTERFACE_CSI2A_PHY2, - ISP_INTERFACE_CCP2B_PHY1, - ISP_INTERFACE_CCP2B_PHY2, - ISP_INTERFACE_CSI2C_PHY1, -}; - /* ISP: OMAP 34xx ES 1.0 */ #define ISP_REVISION_1_0 0x10 /* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */ @@ -130,76 +124,6 @@ struct isp_reg { u32 val; }; -/** - * struct isp_parallel_platform_data - Parallel interface platform data - * @data_lane_shift: Data lane shifter - * 0 - CAMEXT[13:0] -> CAM[13:0] - * 1 - CAMEXT[13:2] -> CAM[11:0] - * 2 - CAMEXT[13:4] -> CAM[9:0] - * 3 - CAMEXT[13:6] -> CAM[7:0] - * @clk_pol: Pixel clock polarity - * 0 - Non Inverted, 1 - Inverted - * @bridge: CCDC Bridge input control - * ISPCTRL_PAR_BRIDGE_DISABLE - Disable - * ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian - * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian - */ -struct isp_parallel_platform_data { - unsigned int data_lane_shift:2; - unsigned int clk_pol:1; - unsigned int bridge:4; -}; - -/** - * struct isp_ccp2_platform_data - CCP2 interface platform data - * @strobe_clk_pol: Strobe/clock polarity - * 0 - Non Inverted, 1 - Inverted - * @crc: Enable the cyclic redundancy check - * @ccp2_mode: Enable CCP2 compatibility mode - * 0 - MIPI-CSI1 mode, 1 - CCP2 mode - * @phy_layer: Physical layer selection - * ISPCCP2_CTRL_PHY_SEL_CLOCK - Data/clock physical layer - * ISPCCP2_CTRL_PHY_SEL_STROBE - Data/strobe physical layer - * @vpclk_div: Video port output clock control - */ -struct isp_ccp2_platform_data { - unsigned int strobe_clk_pol:1; - unsigned int crc:1; - unsigned int ccp2_mode:1; - unsigned int phy_layer:1; - unsigned int vpclk_div:2; -}; - -/** - * struct isp_csi2_platform_data - CSI2 interface platform data - * @crc: Enable the cyclic redundancy check - * @vpclk_div: Video port output clock control - */ -struct isp_csi2_platform_data { - unsigned crc:1; - unsigned vpclk_div:2; -}; - -struct isp_subdev_i2c_board_info { - struct i2c_board_info *board_info; - int i2c_adapter_id; -}; - -struct isp_v4l2_subdevs_group { - struct isp_subdev_i2c_board_info *subdevs; - enum isp_interface_type interface; - union { - struct isp_parallel_platform_data parallel; - struct isp_ccp2_platform_data ccp2; - struct isp_csi2_platform_data csi2; - } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ -}; - -struct isp_platform_data { - struct isp_v4l2_subdevs_group *subdevs; - void (*set_constraints)(struct isp_device *isp, bool enable); -}; - struct isp_platform_callback { u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel); int (*csiphy_config)(struct isp_csiphy *phy, @@ -288,7 +212,9 @@ struct isp_device { unsigned int sbl_resources; unsigned int subclk_resources; - struct iommu *iommu; + struct omap_iommu *iommu; + struct iommu_domain *domain; + struct device *iommu_dev; struct isp_platform_callback platform_cb; }; diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 39d501b..a319281 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -31,6 +31,7 @@ #include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/sched.h> +#include <linux/slab.h> #include <media/v4l2-event.h> #include "isp.h" @@ -365,7 +366,7 @@ static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc, dma_unmap_sg(isp->dev, req->iovm->sgt->sgl, req->iovm->sgt->nents, DMA_TO_DEVICE); if (req->table) - iommu_vfree(isp->iommu, req->table); + omap_iommu_vfree(isp->domain, isp->iommu, req->table); kfree(req); } @@ -437,15 +438,15 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, req->enable = 1; - req->table = iommu_vmalloc(isp->iommu, 0, req->config.size, - IOMMU_FLAG); + req->table = omap_iommu_vmalloc(isp->domain, isp->iommu, 0, + req->config.size, IOMMU_FLAG); if (IS_ERR_VALUE(req->table)) { req->table = 0; ret = -ENOMEM; goto done; } - req->iovm = find_iovm_area(isp->iommu, req->table); + req->iovm = omap_find_iovm_area(isp->iommu, req->table); if (req->iovm == NULL) { ret = -ENOMEM; goto done; @@ -461,7 +462,7 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl, req->iovm->sgt->nents, DMA_TO_DEVICE); - table = da_to_va(isp->iommu, req->table); + table = omap_da_to_va(isp->iommu, req->table); if (copy_from_user(table, config->lsc, req->config.size)) { ret = -EFAULT; goto done; @@ -730,18 +731,19 @@ static int ccdc_config(struct isp_ccdc_device *ccdc, /* * table_new must be 64-bytes aligned, but it's - * already done by iommu_vmalloc(). + * already done by omap_iommu_vmalloc(). */ size = ccdc->fpc.fpnum * 4; - table_new = iommu_vmalloc(isp->iommu, 0, size, - IOMMU_FLAG); + table_new = omap_iommu_vmalloc(isp->domain, isp->iommu, + 0, size, IOMMU_FLAG); if (IS_ERR_VALUE(table_new)) return -ENOMEM; - if (copy_from_user(da_to_va(isp->iommu, table_new), + if (copy_from_user(omap_da_to_va(isp->iommu, table_new), (__force void __user *) ccdc->fpc.fpcaddr, size)) { - iommu_vfree(isp->iommu, table_new); + omap_iommu_vfree(isp->domain, isp->iommu, + table_new); return -EFAULT; } @@ -751,7 +753,7 @@ static int ccdc_config(struct isp_ccdc_device *ccdc, ccdc_configure_fpc(ccdc); if (table_old != 0) - iommu_vfree(isp->iommu, table_old); + omap_iommu_vfree(isp->domain, isp->iommu, table_old); } return ccdc_lsc_config(ccdc, ccdc_struct); @@ -1148,6 +1150,8 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) omap3isp_configure_bridge(isp, ccdc->input, pdata, shift); ccdc->syncif.datsz = depth_out; + ccdc->syncif.hdpol = pdata ? pdata->hs_pol : 0; + ccdc->syncif.vdpol = pdata ? pdata->vs_pol : 0; ccdc_config_sync_if(ccdc, &ccdc->syncif); /* CCDC_PAD_SINK */ @@ -1402,11 +1406,13 @@ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) { - struct video_device *vdev = &ccdc->subdev.devnode; + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + struct video_device *vdev = ccdc->subdev.devnode; struct v4l2_event event; memset(&event, 0, sizeof(event)); - event.type = V4L2_EVENT_OMAP3ISP_HS_VS; + event.type = V4L2_EVENT_FRAME_SYNC; + event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number); v4l2_event_queue(vdev, &event); } @@ -1688,10 +1694,14 @@ static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) { - if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS) + if (sub->type != V4L2_EVENT_FRAME_SYNC) + return -EINVAL; + + /* line number is zero at frame start */ + if (sub->id != 0) return -EINVAL; - return v4l2_event_subscribe(fh, sub); + return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS); } static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, @@ -1825,7 +1835,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, * callers to request an output size bigger than the input size * up to the nearest multiple of 16. */ - fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); + fmt->width = clamp_t(u32, width, 32, fmt->width + 15); fmt->width &= ~15; fmt->height = clamp_t(u32, height, 32, fmt->height); break; @@ -2141,6 +2151,37 @@ static const struct media_entity_operations ccdc_media_ops = { .link_setup = ccdc_link_setup, }; +void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) +{ + v4l2_device_unregister_subdev(&ccdc->subdev); + omap3isp_video_unregister(&ccdc->video_out); +} + +int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video node. */ + ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccdc->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccdc_unregister_entities(ccdc); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CCDC initialisation and cleanup + */ + /* * ccdc_init_entities - Initialize V4L2 subdev and media entity * @ccdc: ISP CCDC module @@ -2162,7 +2203,6 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) sd->grp_id = 1 << 16; /* group ID for isp subdevs */ v4l2_set_subdevdata(sd, ccdc); sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - sd->nevents = OMAP3ISP_CCDC_NEVENTS; pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK; pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; @@ -2183,50 +2223,23 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); if (ret < 0) - return ret; + goto error_video; /* Connect the CCDC subdev to the video node. */ ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, &ccdc->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; -} -void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) -{ - media_entity_cleanup(&ccdc->subdev.entity); - - v4l2_device_unregister_subdev(&ccdc->subdev); - omap3isp_video_unregister(&ccdc->video_out); -} - -int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video node. */ - ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccdc->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccdc_unregister_entities(ccdc); +error_link: + omap3isp_video_cleanup(&ccdc->video_out); +error_video: + media_entity_cleanup(me); return ret; } -/* ----------------------------------------------------------------------------- - * ISP CCDC initialisation and cleanup - */ - /* * omap3isp_ccdc_init - CCDC module initialization. * @dev: Device pointer specific to the OMAP3 ISP. @@ -2238,6 +2251,7 @@ error: int omap3isp_ccdc_init(struct isp_device *isp) { struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + int ret; spin_lock_init(&ccdc->lock); init_waitqueue_head(&ccdc->wait); @@ -2257,8 +2271,6 @@ int omap3isp_ccdc_init(struct isp_device *isp) ccdc->syncif.fldout = 0; ccdc->syncif.fldpol = 0; ccdc->syncif.fldstat = 0; - ccdc->syncif.hdpol = 0; - ccdc->syncif.vdpol = 0; ccdc->clamp.oblen = 0; ccdc->clamp.dcsubval = 0; @@ -2268,7 +2280,13 @@ int omap3isp_ccdc_init(struct isp_device *isp) ccdc->update = OMAP3ISP_CCDC_BLCLAMP; ccdc_apply_controls(ccdc); - return ccdc_init_entities(ccdc); + ret = ccdc_init_entities(ccdc); + if (ret < 0) { + mutex_destroy(&ccdc->ioctl_lock); + return ret; + } + + return 0; } /* @@ -2279,6 +2297,9 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) { struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + omap3isp_video_cleanup(&ccdc->video_out); + media_entity_cleanup(&ccdc->subdev.entity); + /* Free LSC requests. As the CCDC is stopped there's no active request, * so only the pending request and the free queue need to be handled. */ @@ -2287,5 +2308,7 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue); if (ccdc->fpc.fpcaddr != 0) - iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr); + omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr); + + mutex_destroy(&ccdc->ioctl_lock); } diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index 0e16cab..904ca8c 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -30,6 +30,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/uaccess.h> +#include <linux/regulator/consumer.h> #include "isp.h" #include "ispreg.h" @@ -163,6 +164,9 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); int i; + if (enable && ccp2->vdds_csib) + regulator_enable(ccp2->vdds_csib); + /* Enable/Disable all the LCx channels */ for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), @@ -186,6 +190,9 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); } + + if (!enable && ccp2->vdds_csib) + regulator_disable(ccp2->vdds_csib); } /* @@ -236,9 +243,9 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); if (!(val & ISPCCP2_CTRL_MODE)) { - if (pdata->ccp2_mode) + if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2) dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); - if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE) + if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE) /* Strobe mode requires CCP2 */ return -EIO; } @@ -1025,6 +1032,48 @@ static const struct media_entity_operations ccp2_media_ops = { }; /* + * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev + * @ccp2: Pointer to ISP CCP2 device + */ +void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) +{ + v4l2_device_unregister_subdev(&ccp2->subdev); + omap3isp_video_unregister(&ccp2->video_in); +} + +/* + * omap3isp_ccp2_register_entities - Register the subdev media entity + * @ccp2: Pointer to ISP CCP2 device + * @vdev: Pointer to v4l device + * return negative error code or zero on success + */ + +int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccp2->video_in, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccp2_unregister_entities(ccp2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP ccp2 initialisation and cleanup + */ + +/* * ccp2_init_entities - Initialize ccp2 subdev and media entity. * @ccp2: Pointer to ISP CCP2 device * return negative error code or zero on success @@ -1076,69 +1125,23 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); if (ret < 0) - return ret; + goto error_video; /* Connect the video node to the ccp2 subdev. */ ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, &ccp2->subdev.entity, CCP2_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; return 0; -} -/* - * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev - * @ccp2: Pointer to ISP CCP2 device - */ -void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) -{ +error_link: + omap3isp_video_cleanup(&ccp2->video_in); +error_video: media_entity_cleanup(&ccp2->subdev.entity); - - v4l2_device_unregister_subdev(&ccp2->subdev); - omap3isp_video_unregister(&ccp2->video_in); -} - -/* - * omap3isp_ccp2_register_entities - Register the subdev media entity - * @ccp2: Pointer to ISP CCP2 device - * @vdev: Pointer to v4l device - * return negative error code or zero on success - */ - -int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccp2->video_in, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccp2_unregister_entities(ccp2); return ret; } -/* ----------------------------------------------------------------------------- - * ISP ccp2 initialisation and cleanup - */ - -/* - * omap3isp_ccp2_cleanup - CCP2 un-initialization - * @isp : Pointer to ISP device - */ -void omap3isp_ccp2_cleanup(struct isp_device *isp) -{ -} - /* * omap3isp_ccp2_init - CCP2 initialization. * @isp : Pointer to ISP device @@ -1151,23 +1154,48 @@ int omap3isp_ccp2_init(struct isp_device *isp) init_waitqueue_head(&ccp2->wait); - /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with + /* + * On the OMAP34xx the CSI1 receiver is operated in the CSIb IO + * complex, which is powered by vdds_csib power rail. Hence the + * request for the regulator. + * + * On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly * configured. * * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c). */ - if (isp->revision == ISP_REVISION_15_0) + if (isp->revision == ISP_REVISION_2_0) { + ccp2->vdds_csib = regulator_get(isp->dev, "vdds_csib"); + if (IS_ERR(ccp2->vdds_csib)) { + dev_dbg(isp->dev, + "Could not get regulator vdds_csib\n"); + ccp2->vdds_csib = NULL; + } + } else if (isp->revision == ISP_REVISION_15_0) { ccp2->phy = &isp->isp_csiphy1; + } ret = ccp2_init_entities(ccp2); - if (ret < 0) - goto out; + if (ret < 0) { + regulator_put(ccp2->vdds_csib); + return ret; + } ccp2_reset(ccp2); -out: - if (ret) - omap3isp_ccp2_cleanup(isp); + return 0; +} - return ret; +/* + * omap3isp_ccp2_cleanup - CCP2 un-initialization + * @isp : Pointer to ISP device + */ +void omap3isp_ccp2_cleanup(struct isp_device *isp) +{ + struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; + + omap3isp_video_cleanup(&ccp2->video_in); + media_entity_cleanup(&ccp2->subdev.entity); + + regulator_put(ccp2->vdds_csib); } diff --git a/drivers/media/video/omap3isp/ispccp2.h b/drivers/media/video/omap3isp/ispccp2.h index 5505a86..6674e9d 100644 --- a/drivers/media/video/omap3isp/ispccp2.h +++ b/drivers/media/video/omap3isp/ispccp2.h @@ -81,6 +81,7 @@ struct isp_ccp2_device { struct isp_interface_mem_config mem_cfg; struct isp_video video_in; struct isp_csiphy *phy; + struct regulator *vdds_csib; unsigned int error; enum isp_pipeline_stream_state state; wait_queue_head_t wait; diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 69161a6..0c5f1cb 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -1187,6 +1187,37 @@ static const struct media_entity_operations csi2_media_ops = { .link_setup = csi2_link_setup, }; +void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) +{ + v4l2_device_unregister_subdev(&csi2->subdev); + omap3isp_video_unregister(&csi2->video_out); +} + +int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &csi2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&csi2->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_csi2_unregister_entities(csi2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CSI2 initialisation and cleanup + */ + /* * csi2_init_entities - Initialize subdev and media entity. * @csi2: Pointer to csi2 structure. @@ -1228,57 +1259,23 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); if (ret < 0) - return ret; + goto error_video; /* Connect the CSI2 subdev to the video node. */ ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, &csi2->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; -} -void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) -{ +error_link: + omap3isp_video_cleanup(&csi2->video_out); +error_video: media_entity_cleanup(&csi2->subdev.entity); - - v4l2_device_unregister_subdev(&csi2->subdev); - omap3isp_video_unregister(&csi2->video_out); -} - -int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &csi2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&csi2->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_csi2_unregister_entities(csi2); return ret; } -/* ----------------------------------------------------------------------------- - * ISP CSI2 initialisation and cleanup - */ - -/* - * omap3isp_csi2_cleanup - Routine for module driver cleanup - */ -void omap3isp_csi2_cleanup(struct isp_device *isp) -{ -} - /* * omap3isp_csi2_init - Routine for module driver init */ @@ -1298,7 +1295,7 @@ int omap3isp_csi2_init(struct isp_device *isp) ret = csi2_init_entities(csi2a); if (ret < 0) - goto fail; + return ret; if (isp->revision == ISP_REVISION_15_0) { csi2c->isp = isp; @@ -1311,7 +1308,15 @@ int omap3isp_csi2_init(struct isp_device *isp) } return 0; -fail: - omap3isp_csi2_cleanup(isp); - return ret; +} + +/* + * omap3isp_csi2_cleanup - Routine for module driver cleanup + */ +void omap3isp_csi2_cleanup(struct isp_device *isp) +{ + struct isp_csi2_device *csi2a = &isp->isp_csi2a; + + omap3isp_video_cleanup(&csi2a->video_out); + media_entity_cleanup(&csi2a->subdev.entity); } diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c index 8068cef..a3c76bf 100644 --- a/drivers/media/video/omap3isp/isph3a_aewb.c +++ b/drivers/media/video/omap3isp/isph3a_aewb.c @@ -370,5 +370,5 @@ void omap3isp_h3a_aewb_cleanup(struct isp_device *isp) { kfree(isp->isp_aewb.priv); kfree(isp->isp_aewb.recover_priv); - omap3isp_stat_free(&isp->isp_aewb); + omap3isp_stat_cleanup(&isp->isp_aewb); } diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c index ba54d0a..58e0bc4 100644 --- a/drivers/media/video/omap3isp/isph3a_af.c +++ b/drivers/media/video/omap3isp/isph3a_af.c @@ -425,5 +425,5 @@ void omap3isp_h3a_af_cleanup(struct isp_device *isp) { kfree(isp->isp_af.priv); kfree(isp->isp_af.recover_priv); - omap3isp_stat_free(&isp->isp_af); + omap3isp_stat_cleanup(&isp->isp_af); } diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c index 1743856..1163907 100644 --- a/drivers/media/video/omap3isp/isphist.c +++ b/drivers/media/video/omap3isp/isphist.c @@ -516,5 +516,5 @@ void omap3isp_hist_cleanup(struct isp_device *isp) if (HIST_USING_DMA(&isp->isp_hist)) omap_free_dma(isp->isp_hist.dma_ch); kfree(isp->isp_hist.priv); - omap3isp_stat_free(&isp->isp_hist); + omap3isp_stat_cleanup(&isp->isp_hist); } diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index aba537a..ccb876f 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -76,9 +76,51 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define DEF_DETECT_CORRECT_VAL 0xe -#define PREV_MIN_WIDTH 64 -#define PREV_MIN_HEIGHT 8 -#define PREV_MAX_HEIGHT 16384 +/* + * Margins and image size limits. + * + * The preview engine crops several rows and columns internally depending on + * which filters are enabled. To avoid format changes when the filters are + * enabled or disabled (which would prevent them from being turned on or off + * during streaming), the driver assumes all the filters are enabled when + * computing sink crop and source format limits. + * + * If a filter is disabled, additional cropping is automatically added at the + * preview engine input by the driver to avoid overflow at line and frame end. + * This is completely transparent for applications. + * + * Median filter 4 pixels + * Noise filter, + * Faulty pixels correction 4 pixels, 4 lines + * CFA filter 4 pixels, 4 lines in Bayer mode + * 2 lines in other modes + * Color suppression 2 pixels + * or luma enhancement + * ------------------------------------------------------------- + * Maximum total 14 pixels, 8 lines + * + * The color suppression and luma enhancement filters are applied after bayer to + * YUV conversion. They thus can crop one pixel on the left and one pixel on the + * right side of the image without changing the color pattern. When both those + * filters are disabled, the driver must crop the two pixels on the same side of + * the image to avoid changing the bayer pattern. The left margin is thus set to + * 8 pixels and the right margin to 6 pixels. + */ + +#define PREV_MARGIN_LEFT 8 +#define PREV_MARGIN_RIGHT 6 +#define PREV_MARGIN_TOP 4 +#define PREV_MARGIN_BOTTOM 4 + +#define PREV_MIN_IN_WIDTH 64 +#define PREV_MIN_IN_HEIGHT 8 +#define PREV_MAX_IN_HEIGHT 16384 + +#define PREV_MIN_OUT_WIDTH 0 +#define PREV_MIN_OUT_HEIGHT 0 +#define PREV_MAX_OUT_WIDTH 1280 +#define PREV_MAX_OUT_WIDTH_ES2 3300 +#define PREV_MAX_OUT_WIDTH_3630 4096 /* * Coeficient Tables for the submodules in Preview. @@ -979,52 +1021,36 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) * enabled when reporting source pad formats to userspace. If this assumption is * not true, rows and columns must be manually cropped at the preview engine * input to avoid overflows at the end of lines and frames. + * + * See the explanation at the PREV_MARGIN_* definitions for more details. */ static void preview_config_input_size(struct isp_prev_device *prev) { struct isp_device *isp = to_isp_device(prev); struct prev_params *params = &prev->params; - struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; - unsigned int sph = 0; - unsigned int eph = format->width - 1; - unsigned int slv = 0; - unsigned int elv = format->height - 1; - - if (prev->input == PREVIEW_INPUT_CCDC) { - sph += 2; - eph -= 2; + unsigned int sph = prev->crop.left; + unsigned int eph = prev->crop.left + prev->crop.width - 1; + unsigned int slv = prev->crop.top; + unsigned int elv = prev->crop.top + prev->crop.height - 1; + + if (params->features & PREV_CFA) { + sph -= 2; + eph += 2; + slv -= 2; + elv += 2; } - - /* - * Median filter 4 pixels - * Noise filter 4 pixels, 4 lines - * or faulty pixels correction - * CFA filter 4 pixels, 4 lines in Bayer mode - * 2 lines in other modes - * Color suppression 2 pixels - * or luma enhancement - * ------------------------------------------------------------- - * Maximum total 14 pixels, 8 lines - */ - - if (!(params->features & PREV_CFA)) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; + if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) { + sph -= 2; + eph += 2; + slv -= 2; + elv += 2; } - if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; + if (params->features & PREV_HORZ_MEDIAN_FILTER) { + sph -= 2; + eph += 2; } - if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { - sph += 2; - eph -= 2; - } - if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) - sph += 2; + if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)) + sph -= 2; isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); @@ -1228,7 +1254,6 @@ static void preview_init_params(struct isp_prev_device *prev) /* Init values */ params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; - params->average = NO_AVE; params->cfa.format = OMAP3ISP_CFAFMT_BAYER; memcpy(params->cfa.table, cfa_coef_table, sizeof(params->cfa.table)); @@ -1281,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) switch (isp->revision) { case ISP_REVISION_1_0: - return ISPPRV_MAXOUTPUT_WIDTH; + return PREV_MAX_OUT_WIDTH; case ISP_REVISION_2_0: default: - return ISPPRV_MAXOUTPUT_WIDTH_ES2; + return PREV_MAX_OUT_WIDTH_ES2; case ISP_REVISION_15_0: - return ISPPRV_MAXOUTPUT_WIDTH_3630; + return PREV_MAX_OUT_WIDTH_3630; } } @@ -1296,8 +1321,6 @@ static void preview_configure(struct isp_prev_device *prev) { struct isp_device *isp = to_isp_device(prev); struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; - unsigned int format_avg; preview_setup_hw(prev); @@ -1335,10 +1358,7 @@ static void preview_configure(struct isp_prev_device *prev) preview_config_outlineoffset(prev, ALIGN(format->width, 0x10) * 2); - max_out_width = preview_max_out_width(prev); - - format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); - preview_config_averager(prev, format_avg); + preview_config_averager(prev, 0); preview_config_ycpos(prev, format->code); } @@ -1597,6 +1617,16 @@ __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, return &prev->formats[pad]; } +static struct v4l2_rect * +__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); + else + return &prev->crop; +} + /* previewer format descriptions */ static const unsigned int preview_input_fmts[] = { V4L2_MBUS_FMT_SGRBG10_1X10, @@ -1611,24 +1641,25 @@ static const unsigned int preview_output_fmts[] = { }; /* - * preview_try_format - Handle try format by pad subdev method - * @prev: ISP preview device - * @fh : V4L2 subdev file handle - * @pad: pad num - * @fmt: pointer to v4l2 format structure + * preview_try_format - Validate a format + * @prev: ISP preview engine + * @fh: V4L2 subdev file handle + * @pad: pad number + * @fmt: format to be validated + * @which: try/active format selector + * + * Validate and adjust the given format for the given pad based on the preview + * engine limits and the format and crop rectangles on other pads. */ static void preview_try_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { - struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; enum v4l2_mbus_pixelcode pixelcode; + struct v4l2_rect *crop; unsigned int i; - max_out_width = preview_max_out_width(prev); - switch (pad) { case PREV_PAD_SINK: /* When reading data from the CCDC, the input size has already @@ -1641,10 +1672,11 @@ static void preview_try_format(struct isp_prev_device *prev, * filter array interpolation. */ if (prev->input == PREVIEW_INPUT_MEMORY) { - fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, - max_out_width * 8); - fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, - PREV_MAX_HEIGHT); + fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH, + preview_max_out_width(prev)); + fmt->height = clamp_t(u32, fmt->height, + PREV_MIN_IN_HEIGHT, + PREV_MAX_IN_HEIGHT); } fmt->colorspace = V4L2_COLORSPACE_SRGB; @@ -1661,15 +1693,8 @@ static void preview_try_format(struct isp_prev_device *prev, case PREV_PAD_SOURCE: pixelcode = fmt->code; - format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); + *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); - /* The preview module output size is configurable through the - * input interface (horizontal and vertical cropping) and the - * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In - * spite of this, hardcode the output size to the biggest - * possible value for simplicity reasons. - */ switch (pixelcode) { case V4L2_MBUS_FMT_YUYV8_1X16: case V4L2_MBUS_FMT_UYVY8_1X16: @@ -1681,31 +1706,14 @@ static void preview_try_format(struct isp_prev_device *prev, break; } - /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped - * from the left and right sides when the input source is the - * CCDC. This seems not to be needed in practice, investigation - * is required. - */ - if (prev->input == PREVIEW_INPUT_CCDC) - fmt->width -= 4; - - /* The preview module can output a maximum of 3312 pixels - * horizontally due to fixed memory-line sizes. Compute the - * horizontal averaging factor accordingly. Note that the limit - * applies to the noise filter and CFA interpolation blocks, so - * it doesn't take cropping by further blocks into account. - * - * ES 1.0 hardware revision is limited to 1280 pixels - * horizontally. - */ - fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); - - /* Assume that all blocks are enabled and crop pixels and lines - * accordingly. See preview_config_input_size() for more - * information. + /* The preview module output size is configurable through the + * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This + * is not supported yet, hardcode the output size to the crop + * rectangle size. */ - fmt->width -= 14; - fmt->height -= 8; + crop = __preview_get_crop(prev, fh, which); + fmt->width = crop->width; + fmt->height = crop->height; fmt->colorspace = V4L2_COLORSPACE_JPEG; break; @@ -1715,6 +1723,49 @@ static void preview_try_format(struct isp_prev_device *prev, } /* + * preview_try_crop - Validate a crop rectangle + * @prev: ISP preview engine + * @sink: format on the sink pad + * @crop: crop rectangle to be validated + * + * The preview engine crops lines and columns for its internal operation, + * depending on which filters are enabled. Enforce minimum crop margins to + * handle that transparently for userspace. + * + * See the explanation at the PREV_MARGIN_* definitions for more details. + */ +static void preview_try_crop(struct isp_prev_device *prev, + const struct v4l2_mbus_framefmt *sink, + struct v4l2_rect *crop) +{ + unsigned int left = PREV_MARGIN_LEFT; + unsigned int right = sink->width - PREV_MARGIN_RIGHT; + unsigned int top = PREV_MARGIN_TOP; + unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM; + + /* When processing data on-the-fly from the CCDC, at least 2 pixels must + * be cropped from the left and right sides of the image. As we don't + * know which filters will be enabled, increase the left and right + * margins by two. + */ + if (prev->input == PREVIEW_INPUT_CCDC) { + left += 2; + right -= 2; + } + + /* Restrict left/top to even values to keep the Bayer pattern. */ + crop->left &= ~1; + crop->top &= ~1; + + crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH); + crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT); + crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH, + right - crop->left); + crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT, + bottom - crop->top); +} + +/* * preview_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure * @fh : V4L2 subdev file handle @@ -1776,6 +1827,60 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, } /* + * preview_get_crop - Retrieve the crop rectangle on a pad + * @sd: ISP preview V4L2 subdevice + * @fh: V4L2 subdev file handle + * @crop: crop rectangle + * + * Return 0 on success or a negative error code otherwise. + */ +static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + + /* Cropping is only supported on the sink pad. */ + if (crop->pad != PREV_PAD_SINK) + return -EINVAL; + + crop->rect = *__preview_get_crop(prev, fh, crop->which); + return 0; +} + +/* + * preview_set_crop - Retrieve the crop rectangle on a pad + * @sd: ISP preview V4L2 subdevice + * @fh: V4L2 subdev file handle + * @crop: crop rectangle + * + * Return 0 on success or a negative error code otherwise. + */ +static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + /* Cropping is only supported on the sink pad. */ + if (crop->pad != PREV_PAD_SINK) + return -EINVAL; + + /* The crop rectangle can't be changed while streaming. */ + if (prev->state != ISP_PIPELINE_STREAM_STOPPED) + return -EBUSY; + + format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which); + preview_try_crop(prev, format, &crop->rect); + *__preview_get_crop(prev, fh, crop->which) = crop->rect; + + /* Update the source format. */ + format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which); + preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which); + + return 0; +} + +/* * preview_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure * @fh : V4L2 subdev file handle @@ -1808,6 +1913,7 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; format = __preview_get_format(prev, fh, fmt->pad, fmt->which); if (format == NULL) @@ -1818,9 +1924,18 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* Propagate the format from sink to source */ if (fmt->pad == PREV_PAD_SINK) { + /* Reset the crop rectangle. */ + crop = __preview_get_crop(prev, fh, fmt->which); + crop->left = 0; + crop->top = 0; + crop->width = fmt->format.width; + crop->height = fmt->format.height; + + preview_try_crop(prev, &fmt->format, crop); + + /* Update the source format. */ format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, fmt->which); - *format = fmt->format; preview_try_format(prev, fh, PREV_PAD_SOURCE, format, fmt->which); } @@ -1869,6 +1984,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { .enum_frame_size = preview_enum_frame_size, .get_fmt = preview_get_format, .set_fmt = preview_set_format, + .get_crop = preview_get_crop, + .set_crop = preview_set_crop, }; /* subdev operations */ @@ -1966,8 +2083,44 @@ static const struct media_entity_operations preview_media_ops = { .link_setup = preview_link_setup, }; +void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) +{ + v4l2_device_unregister_subdev(&prev->subdev); + omap3isp_video_unregister(&prev->video_in); + omap3isp_video_unregister(&prev->video_out); +} + +int omap3isp_preview_register_entities(struct isp_prev_device *prev, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &prev->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_preview_unregister_entities(prev); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP previewer initialisation and cleanup + */ + /* - * review_init_entities - Initialize subdev and media entity. + * preview_init_entities - Initialize subdev and media entity. * @prev : Pointer to preview structure * return -ENOMEM or zero on success */ @@ -2024,69 +2177,34 @@ static int preview_init_entities(struct isp_prev_device *prev) ret = omap3isp_video_init(&prev->video_in, "preview"); if (ret < 0) - return ret; + goto error_video_in; ret = omap3isp_video_init(&prev->video_out, "preview"); if (ret < 0) - return ret; + goto error_video_out; /* Connect the video nodes to the previewer subdev. */ ret = media_entity_create_link(&prev->video_in.video.entity, 0, &prev->subdev.entity, PREV_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, &prev->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; -} -void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) -{ +error_link: + omap3isp_video_cleanup(&prev->video_out); +error_video_out: + omap3isp_video_cleanup(&prev->video_in); +error_video_in: media_entity_cleanup(&prev->subdev.entity); - - v4l2_device_unregister_subdev(&prev->subdev); - v4l2_ctrl_handler_free(&prev->ctrls); - omap3isp_video_unregister(&prev->video_in); - omap3isp_video_unregister(&prev->video_out); -} - -int omap3isp_preview_register_entities(struct isp_prev_device *prev, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &prev->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_preview_unregister_entities(prev); return ret; } -/* ----------------------------------------------------------------------------- - * ISP previewer initialisation and cleanup - */ - -void omap3isp_preview_cleanup(struct isp_device *isp) -{ -} - /* * isp_preview_init - Previewer initialization. * @dev : Pointer to ISP device @@ -2095,19 +2213,20 @@ void omap3isp_preview_cleanup(struct isp_device *isp) int omap3isp_preview_init(struct isp_device *isp) { struct isp_prev_device *prev = &isp->isp_prev; - int ret; spin_lock_init(&prev->lock); init_waitqueue_head(&prev->wait); preview_init_params(prev); - ret = preview_init_entities(prev); - if (ret < 0) - goto out; + return preview_init_entities(prev); +} -out: - if (ret) - omap3isp_preview_cleanup(isp); +void omap3isp_preview_cleanup(struct isp_device *isp) +{ + struct isp_prev_device *prev = &isp->isp_prev; - return ret; + v4l2_ctrl_handler_free(&prev->ctrls); + omap3isp_video_cleanup(&prev->video_in); + omap3isp_video_cleanup(&prev->video_out); + media_entity_cleanup(&prev->subdev.entity); } diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index fa943bd..f54e775 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -45,11 +45,6 @@ #define ISPPRV_CONTRAST_HIGH 0xFF #define ISPPRV_CONTRAST_UNITS 0x1 -#define NO_AVE 0x0 -#define AVE_2_PIX 0x1 -#define AVE_4_PIX 0x2 -#define AVE_8_PIX 0x3 - /* Features list */ #define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH #define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW @@ -106,7 +101,6 @@ enum preview_ycpos_mode { * @rgb2ycbcr: RGB to ycbcr parameters. * @hmed: Horizontal median filter. * @yclimit: YC limits parameters. - * @average: Downsampling rate for averager. * @contrast: Contrast. * @brightness: Brightness. */ @@ -124,7 +118,6 @@ struct prev_params { struct omap3isp_prev_csc rgb2ycbcr; struct omap3isp_prev_hmed hmed; struct omap3isp_prev_yclimit yclimit; - u8 average; u8 contrast; u8 brightness; }; @@ -159,6 +152,7 @@ struct isptables_update { * @subdev: V4L2 subdevice * @pads: Media entity pads * @formats: Active formats at the subdev pad + * @crop: Active crop rectangle * @input: Module currently connected to the input pad * @output: Bitmask of the active output * @video_in: Input video entity @@ -177,6 +171,7 @@ struct isp_prev_device { struct v4l2_subdev subdev; struct media_pad pads[PREV_PADS_NUM]; struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; + struct v4l2_rect crop; struct v4l2_ctrl_handler ctrls; diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index 9c31714..9bebb1e 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -868,6 +868,10 @@ int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, goto done; if (vbuf->memory == V4L2_MEMORY_USERPTR && + vbuf->length < buf->vbuf.length) + goto done; + + if (vbuf->memory == V4L2_MEMORY_USERPTR && vbuf->m.userptr != buf->vbuf.m.userptr) { isp_video_buffer_cleanup(buf); buf->vbuf.m.userptr = vbuf->m.userptr; diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/video/omap3isp/ispreg.h index 69f6af6..084ea77 100644 --- a/drivers/media/video/omap3isp/ispreg.h +++ b/drivers/media/video/omap3isp/ispreg.h @@ -402,9 +402,6 @@ #define ISPPRV_YENH_TABLE_ADDR 0x1000 #define ISPPRV_CFA_TABLE_ADDR 0x1400 -#define ISPPRV_MAXOUTPUT_WIDTH 1280 -#define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300 -#define ISPPRV_MAXOUTPUT_WIDTH_3630 4096 #define ISPRSZ_MIN_OUTPUT 64 #define ISPRSZ_MAX_OUTPUT 3312 diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 0bb0f8c..50e593b 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1608,6 +1608,42 @@ static const struct media_entity_operations resizer_media_ops = { .link_setup = resizer_link_setup, }; +void omap3isp_resizer_unregister_entities(struct isp_res_device *res) +{ + v4l2_device_unregister_subdev(&res->subdev); + omap3isp_video_unregister(&res->video_in); + omap3isp_video_unregister(&res->video_out); +} + +int omap3isp_resizer_register_entities(struct isp_res_device *res, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &res->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_resizer_unregister_entities(res); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP resizer initialization and cleanup + */ + /* * resizer_init_entities - Initialize resizer subdev and media entity. * @res : Pointer to resizer device structure @@ -1652,68 +1688,34 @@ static int resizer_init_entities(struct isp_res_device *res) ret = omap3isp_video_init(&res->video_in, "resizer"); if (ret < 0) - return ret; + goto error_video_in; ret = omap3isp_video_init(&res->video_out, "resizer"); if (ret < 0) - return ret; + goto error_video_out; /* Connect the video nodes to the resizer subdev. */ ret = media_entity_create_link(&res->video_in.video.entity, 0, &res->subdev.entity, RESZ_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, &res->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; -} -void omap3isp_resizer_unregister_entities(struct isp_res_device *res) -{ +error_link: + omap3isp_video_cleanup(&res->video_out); +error_video_out: + omap3isp_video_cleanup(&res->video_in); +error_video_in: media_entity_cleanup(&res->subdev.entity); - - v4l2_device_unregister_subdev(&res->subdev); - omap3isp_video_unregister(&res->video_in); - omap3isp_video_unregister(&res->video_out); -} - -int omap3isp_resizer_register_entities(struct isp_res_device *res, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &res->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_resizer_unregister_entities(res); return ret; } -/* ----------------------------------------------------------------------------- - * ISP resizer initialization and cleanup - */ - -void omap3isp_resizer_cleanup(struct isp_device *isp) -{ -} - /* * isp_resizer_init - Resizer initialization. * @isp : Pointer to ISP device @@ -1722,17 +1724,17 @@ void omap3isp_resizer_cleanup(struct isp_device *isp) int omap3isp_resizer_init(struct isp_device *isp) { struct isp_res_device *res = &isp->isp_res; - int ret; init_waitqueue_head(&res->wait); atomic_set(&res->stopping, 0); - ret = resizer_init_entities(res); - if (ret < 0) - goto out; + return resizer_init_entities(res); +} -out: - if (ret) - omap3isp_resizer_cleanup(isp); +void omap3isp_resizer_cleanup(struct isp_device *isp) +{ + struct isp_res_device *res = &isp->isp_res; - return ret; + omap3isp_video_cleanup(&res->video_in); + omap3isp_video_cleanup(&res->video_out); + media_entity_cleanup(&res->subdev.entity); } diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index b44cb68..bc0b2c7 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -366,7 +366,8 @@ static void isp_stat_bufs_free(struct ispstat *stat) dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl, buf->iovm->sgt->nents, DMA_FROM_DEVICE); - iommu_vfree(isp->iommu, buf->iommu_addr); + omap_iommu_vfree(isp->domain, isp->iommu, + buf->iommu_addr); } else { if (!buf->virt_addr) continue; @@ -399,8 +400,8 @@ static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size) struct iovm_struct *iovm; WARN_ON(buf->dma_addr); - buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size, - IOMMU_FLAG); + buf->iommu_addr = omap_iommu_vmalloc(isp->domain, isp->iommu, 0, + size, IOMMU_FLAG); if (IS_ERR((void *)buf->iommu_addr)) { dev_err(stat->isp->dev, "%s: Can't acquire memory for " @@ -409,7 +410,7 @@ static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size) return -ENOMEM; } - iovm = find_iovm_area(isp->iommu, buf->iommu_addr); + iovm = omap_find_iovm_area(isp->iommu, buf->iommu_addr); if (!iovm || !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents, DMA_FROM_DEVICE)) { @@ -418,7 +419,7 @@ static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size) } buf->iovm = iovm; - buf->virt_addr = da_to_va(stat->isp->iommu, + buf->virt_addr = omap_da_to_va(stat->isp->iommu, (u32)buf->iommu_addr); buf->empty = 1; dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated." @@ -495,7 +496,7 @@ static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) static void isp_stat_queue_event(struct ispstat *stat, int err) { - struct video_device *vdev = &stat->subdev.devnode; + struct video_device *vdev = stat->subdev.devnode; struct v4l2_event event; struct omap3isp_stat_event_status *status = (void *)event.u.data; @@ -1022,25 +1023,6 @@ void omap3isp_stat_dma_isr(struct ispstat *stat) __stat_isr(stat, 1); } -static int isp_stat_init_entities(struct ispstat *stat, const char *name, - const struct v4l2_subdev_ops *sd_ops) -{ - struct v4l2_subdev *subdev = &stat->subdev; - struct media_entity *me = &subdev->entity; - - v4l2_subdev_init(subdev, sd_ops); - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); - subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ - subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - subdev->nevents = STAT_NEVENTS; - v4l2_set_subdevdata(subdev, stat); - - stat->pad.flags = MEDIA_PAD_FL_SINK; - me->ops = NULL; - - return media_entity_init(me, 1, &stat->pad, 0); -} - int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) @@ -1050,7 +1032,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, if (sub->type != stat->event_type) return -EINVAL; - return v4l2_event_subscribe(fh, sub); + return v4l2_event_subscribe(fh, sub, STAT_NEVENTS); } int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, @@ -1062,7 +1044,6 @@ int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, void omap3isp_stat_unregister_entities(struct ispstat *stat) { - media_entity_cleanup(&stat->subdev.entity); v4l2_device_unregister_subdev(&stat->subdev); } @@ -1072,21 +1053,50 @@ int omap3isp_stat_register_entities(struct ispstat *stat, return v4l2_device_register_subdev(vdev, &stat->subdev); } +static int isp_stat_init_entities(struct ispstat *stat, const char *name, + const struct v4l2_subdev_ops *sd_ops) +{ + struct v4l2_subdev *subdev = &stat->subdev; + struct media_entity *me = &subdev->entity; + + v4l2_subdev_init(subdev, sd_ops); + snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); + subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ + subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_set_subdevdata(subdev, stat); + + stat->pad.flags = MEDIA_PAD_FL_SINK; + me->ops = NULL; + + return media_entity_init(me, 1, &stat->pad, 0); +} + int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops) { + int ret; + stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); if (!stat->buf) return -ENOMEM; + isp_stat_buf_clear(stat); mutex_init(&stat->ioctl_lock); atomic_set(&stat->buf_err, 0); - return isp_stat_init_entities(stat, name, sd_ops); + ret = isp_stat_init_entities(stat, name, sd_ops); + if (ret < 0) { + mutex_destroy(&stat->ioctl_lock); + kfree(stat->buf); + } + + return ret; } -void omap3isp_stat_free(struct ispstat *stat) +void omap3isp_stat_cleanup(struct ispstat *stat) { + media_entity_cleanup(&stat->subdev.entity); + mutex_destroy(&stat->ioctl_lock); isp_stat_bufs_free(stat); kfree(stat->buf); } diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index d86da94..9b7c865 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h @@ -144,7 +144,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, struct omap3isp_stat_data *data); int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops); -void omap3isp_stat_free(struct ispstat *stat); +void omap3isp_stat_cleanup(struct ispstat *stat); int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, struct v4l2_event_subscription *sub); diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 9cd8f1a..f229057 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -26,6 +26,7 @@ #include <asm/cacheflush.h> #include <linux/clk.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> #include <linux/sched.h> @@ -278,7 +279,8 @@ isp_video_far_end(struct isp_video *video) * limits reported by every block in the pipeline. * * Return 0 if all formats match, or -EPIPE if at least one link is found with - * different formats on its two ends. + * different formats on its two ends or if the pipeline doesn't start with a + * video source (either a subdev with no input pad, or a non-subdev entity). */ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) { @@ -329,10 +331,15 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) * in the middle of it. */ shifter_link = subdev == &isp->isp_ccdc.subdev; - /* Retrieve the source format */ + /* Retrieve the source format. Return an error if no source + * entity can be found, and stop checking the pipeline if the + * source entity isn't a subdev. + */ pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (pad == NULL) + return -EPIPE; + + if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) break; subdev = media_entity_to_v4l2_subdev(pad->entity); @@ -446,7 +453,7 @@ ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) sgt->nents = sglen; sgt->orig_nents = sglen; - da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG); + da = omap_iommu_vmap(isp->domain, isp->iommu, 0, sgt, IOMMU_FLAG); if (IS_ERR_VALUE(da)) kfree(sgt); @@ -462,7 +469,7 @@ static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) { struct sg_table *sgt; - sgt = iommu_vunmap(isp->iommu, (u32)da); + sgt = omap_iommu_vunmap(isp->domain, isp->iommu, (u32)da); kfree(sgt); } @@ -695,7 +702,6 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); strlcpy(cap->card, video->video.name, sizeof(cap->card)); strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); - cap->version = ISP_VIDEO_DRIVER_VERSION; if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; @@ -1051,6 +1057,14 @@ error: if (video->isp->pdata->set_constraints) video->isp->pdata->set_constraints(video->isp, false); media_entity_pipeline_stop(&video->video.entity); + /* The DMA queue must be emptied here, otherwise CCDC interrupts + * that will get triggered the next time the CCDC is powered up + * will try to access buffers that might have been freed but + * still present in the DMA queue. This can easily get triggered + * if the above omap3isp_pipeline_set_stream() call fails on a + * system with a free-running sensor. + */ + INIT_LIST_HEAD(&video->dmaqueue); video->queue = NULL; } @@ -1312,6 +1326,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name) return 0; } +void omap3isp_video_cleanup(struct isp_video *video) +{ + media_entity_cleanup(&video->video.entity); + mutex_destroy(&video->stream_lock); + mutex_destroy(&video->mutex); +} + int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) { int ret; @@ -1328,8 +1349,6 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) void omap3isp_video_unregister(struct isp_video *video) { - if (video_is_registered(&video->video)) { - media_entity_cleanup(&video->video.entity); + if (video_is_registered(&video->video)) video_unregister_device(&video->video); - } } diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 911bea6..08cbfa1 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -27,7 +27,6 @@ #define OMAP3_ISP_VIDEO_H #include <linux/v4l2-mediabus.h> -#include <linux/version.h> #include <media/media-entity.h> #include <media/v4l2-dev.h> #include <media/v4l2-fh.h> @@ -35,7 +34,7 @@ #include "ispqueue.h" #define ISP_VIDEO_DRIVER_NAME "ispvideo" -#define ISP_VIDEO_DRIVER_VERSION KERNEL_VERSION(0, 0, 1) +#define ISP_VIDEO_DRIVER_VERSION "0.0.2" struct isp_device; struct isp_video; @@ -191,6 +190,7 @@ struct isp_video_fh { container_of(q, struct isp_video_fh, queue) int omap3isp_video_init(struct isp_video *video, const char *name); +void omap3isp_video_cleanup(struct isp_video *video); int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev); void omap3isp_video_unregister(struct isp_video *video); diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index de2fc14..c17f37d 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -16,7 +16,7 @@ pvrusb2-objs := pvrusb2-i2c-core.o \ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index c4eca15..d8c8982 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -28,6 +28,7 @@ pvr2_device_desc structures. #include "pvrusb2-devattr.h" #include <linux/usb.h> +#include <linux/module.h> /* This is needed in order to pull in tuner type ids... */ #include <linux/i2c.h> #include <media/tuner.h> diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index e98d382..122b457 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -21,6 +21,7 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/firmware.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> @@ -2993,6 +2994,13 @@ static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id, pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \ } +int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std) +{ + v4l2_device_call_all(&hdw->v4l2_dev, 0, + video, querystd, std); + return 0; +} + /* Execute whatever commands are required to update the state of all the sub-devices so that they match our current control values. */ static void pvr2_subdev_update(struct pvr2_hdw *hdw) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index d7753ae..6654658 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -214,6 +214,9 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std, unsigned int idx); +/* Get the detected video standard */ +int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std); + /* Enable / disable retrieval of CPU firmware or prom contents. This must be enabled before pvr2_hdw_cpufw_get() will function. Note that doing this may prevent the device from running (and leaving this mode may diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index e72d510..885ce11 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -19,6 +19,7 @@ */ #include <linux/i2c.h> +#include <linux/module.h> #include <media/ir-kbd-i2c.h> #include "pvrusb2-i2c-core.h" #include "pvrusb2-hdw-internal.h" diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 2254194..c1d9bb6 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -168,6 +168,7 @@ module_exit(pvr_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.9.1"); /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 3876114..6d66617 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -29,6 +29,7 @@ #include "pvrusb2-v4l2.h" #include "pvrusb2-ioread.h" #include <linux/videodev2.h> +#include <linux/module.h> #include <media/v4l2-dev.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> @@ -91,7 +92,7 @@ static struct v4l2_capability pvr_capability ={ .driver = "pvrusb2", .card = "Hauppauge WinTV pvr-usb2", .bus_info = "usb", - .version = KERNEL_VERSION(0, 9, 0), + .version = LINUX_VERSION_CODE, .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | V4L2_CAP_READWRITE), @@ -227,6 +228,14 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) break; } + case VIDIOC_QUERYSTD: + { + v4l2_std_id *std = arg; + *std = V4L2_STD_ALL; + ret = pvr2_hdw_get_detected_std(hdw, std); + break; + } + case VIDIOC_G_STD: { int val = 0; @@ -369,11 +378,6 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) break; } - case VIDIOC_S_AUDIO: - { - ret = -EINVAL; - break; - } case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; @@ -850,7 +854,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) #endif default : - ret = -EINVAL; + ret = -ENOTTY; break; } diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 8a5ff4d..a646ccf 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 10460fd..dbcdfbf 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -172,7 +172,9 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, dev->dmasound.bufsize, dev->dmasound.blocks); spin_unlock(&dev->slock); + snd_pcm_stream_lock(dev->dmasound.substream); snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(dev->dmasound.substream); return; } diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index e2062b2..0f9fb99 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -4951,8 +4951,9 @@ struct saa7134_board saa7134_boards[] = { .audio_clock = 0x00187de7, .tuner_type = TUNER_XC2028, .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, + .tuner_addr = 0x61, .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, .vmux = 3, @@ -6992,6 +6993,11 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev, msleep(10); saa7134_set_gpio(dev, 18, 1); break; + case SAA7134_BOARD_VIDEOMATE_T750: + saa7134_set_gpio(dev, 20, 0); + msleep(10); + saa7134_set_gpio(dev, 20, 1); + break; } return 0; } @@ -7451,6 +7457,11 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0e050000, 0x0c050000); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000); break; + case SAA7134_BOARD_VIDEOMATE_T750: + /* enable the analog tuner */ + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00008000, 0x00008000); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000); + break; } return 0; } diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index f9be737..ca65cda 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -39,6 +39,8 @@ MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); +MODULE_VERSION(SAA7134_VERSION); + /* ------------------------------------------------------------------ */ @@ -1332,14 +1334,8 @@ static struct pci_driver saa7134_pci_driver = { static int __init saa7134_init(void) { INIT_LIST_HEAD(&saa7134_devlist); - printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n", - (SAA7134_VERSION_CODE >> 16) & 0xff, - (SAA7134_VERSION_CODE >> 8) & 0xff, - SAA7134_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif + printk(KERN_INFO "saa7130/34: v4l2 driver version %s loaded\n", + SAA7134_VERSION); return pci_register_driver(&saa7134_pci_driver); } diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 996a206..1e4ef16 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -56,6 +56,7 @@ #include "lgs8gxx.h" #include "zl10353.h" +#include "qt1010.h" #include "zl10036.h" #include "zl10039.h" @@ -939,6 +940,18 @@ static struct zl10353_config behold_x7_config = { .disable_i2c_gate_ctrl = 1, }; +static struct zl10353_config videomate_t750_zl10353_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, +}; + +static struct qt1010_config videomate_t750_qt1010_config = { + .i2c_address = 0x62 +}; + + /* ================================================================== * tda10086 based DVB-S cards, helper functions */ @@ -1650,6 +1663,18 @@ static int dvb_init(struct saa7134_dev *dev) __func__); break; + case SAA7134_BOARD_VIDEOMATE_T750: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &videomate_t750_zl10353_config, + &dev->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (dvb_attach(qt1010_attach, + fe0->dvb.frontend, + &dev->i2c_adap, + &videomate_t750_qt1010_config) == NULL) + wprintk("error attaching QT1010\n"); + } + break; case SAA7134_BOARD_ZOLID_HYBRID_PCI: fe0->dvb.frontend = dvb_attach(tda10048_attach, &zolid_tda10048_config, diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 18294db..dde361a 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -172,7 +172,6 @@ static int empress_querycap(struct file *file, void *priv, strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 776ba2d..9cf7914f 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1810,7 +1810,6 @@ static int saa7134_querycap(struct file *file, void *priv, strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | @@ -2307,7 +2306,6 @@ static int radio_querycap(struct file *file, void *priv, strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 28eb103..9b55068 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -19,8 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/version.h> -#define SAA7134_VERSION_CODE KERNEL_VERSION(0, 2, 16) +#define SAA7134_VERSION "0, 2, 17" #include <linux/pci.h> #include <linux/i2c.h> @@ -844,10 +843,10 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev); int saa7134_ir_start(struct saa7134_dev *dev); void saa7134_ir_stop(struct saa7134_dev *dev); #else -#define saa7134_input_init1(dev) (0) -#define saa7134_input_fini(dev) (0) -#define saa7134_input_irq(dev) (0) -#define saa7134_probe_i2c_ir(dev) (0) -#define saa7134_ir_start(dev) (0) -#define saa7134_ir_stop(dev) (0) +#define saa7134_input_init1(dev) ((void)0) +#define saa7134_input_fini(dev) ((void)0) +#define saa7134_input_irq(dev) ((void)0) +#define saa7134_probe_i2c_ir(dev) ((void)0) +#define saa7134_ir_start(dev) ((void)0) +#define saa7134_ir_stop(dev) ((void)0) #endif diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile index 6303a8e..ecd5811 100644 --- a/drivers/media/video/saa7164/Makefile +++ b/drivers/media/video/saa7164/Makefile @@ -4,9 +4,9 @@ saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c index c713691..971591d 100644 --- a/drivers/media/video/saa7164/saa7164-cards.c +++ b/drivers/media/video/saa7164/saa7164-cards.c @@ -447,6 +447,62 @@ struct saa7164_board saa7164_boards[] = { .i2c_reg_len = REGLEN_8bit, } }, }, + [SAA7164_BOARD_HAUPPAUGE_HVR2200_5] = { + .name = "Hauppauge WinTV-HVR2200", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x23, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x05, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x21, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x22, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x24, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x10 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x25, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x12 >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, }; const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards); @@ -490,6 +546,10 @@ struct saa7164_subid saa7164_subids[] = { .subvendor = 0x0070, .subdevice = 0x8940, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_4, + }, { + .subvendor = 0x0070, + .subdevice = 0x8953, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_5, }, }; const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); @@ -534,6 +594,7 @@ void saa7164_gpio_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: @@ -615,6 +676,7 @@ void saa7164_card_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c index 3b7d7b4..8f3c47e 100644 --- a/drivers/media/video/saa7164/saa7164-core.c +++ b/drivers/media/video/saa7164/saa7164-core.c @@ -1386,9 +1386,11 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev, if (fw_debug) { dev->kthread = kthread_run(saa7164_thread_function, dev, "saa7164 debug"); - if (!dev->kthread) + if (IS_ERR(dev->kthread)) { + dev->kthread = NULL; printk(KERN_ERR "%s() Failed to create " "debug kernel thread\n", __func__); + } } } /* != BOARD_UNKNOWN */ diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c index d377937..5c5cc3e 100644 --- a/drivers/media/video/saa7164/saa7164-dvb.c +++ b/drivers/media/video/saa7164/saa7164-dvb.c @@ -476,6 +476,7 @@ int saa7164_dvb_register(struct saa7164_port *port) case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: i2c_bus = &dev->i2c_bus[port->nr + 1]; switch (port->nr) { case 0: diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c index 4003645..2fd38a0 100644 --- a/drivers/media/video/saa7164/saa7164-encoder.c +++ b/drivers/media/video/saa7164/saa7164-encoder.c @@ -1246,7 +1246,6 @@ static unsigned int fops_poll(struct file *file, poll_table *wait) struct saa7164_encoder_fh *fh = (struct saa7164_encoder_fh *)file->private_data; struct saa7164_port *port = fh->port; - struct saa7164_user_buffer *ubuf; unsigned int mask = 0; port->last_poll_msecs_diff = port->last_poll_msecs; @@ -1278,10 +1277,7 @@ static unsigned int fops_poll(struct file *file, poll_table *wait) } /* Pull the first buffer from the used list */ - ubuf = list_first_entry(&port->list_buf_used.list, - struct saa7164_user_buffer, list); - - if (ubuf) + if (!list_empty(&port->list_buf_used.list)) mask |= POLLIN | POLLRDNORM; return mask; diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c index bc1fced..e2e0341 100644 --- a/drivers/media/video/saa7164/saa7164-vbi.c +++ b/drivers/media/video/saa7164/saa7164-vbi.c @@ -1192,7 +1192,6 @@ static unsigned int fops_poll(struct file *file, poll_table *wait) { struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data; struct saa7164_port *port = fh->port; - struct saa7164_user_buffer *ubuf; unsigned int mask = 0; port->last_poll_msecs_diff = port->last_poll_msecs; @@ -1224,10 +1223,7 @@ static unsigned int fops_poll(struct file *file, poll_table *wait) } /* Pull the first buffer from the used list */ - ubuf = list_first_entry(&port->list_buf_used.list, - struct saa7164_user_buffer, list); - - if (ubuf) + if (!list_empty(&port->list_buf_used.list)) mask |= POLLIN | POLLRDNORM; return mask; diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h index 13bd27e..742b341 100644 --- a/drivers/media/video/saa7164/saa7164.h +++ b/drivers/media/video/saa7164/saa7164.h @@ -48,7 +48,6 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <linux/kdev_t.h> -#include <linux/version.h> #include <linux/mutex.h> #include <linux/crc32.h> #include <linux/kthread.h> @@ -84,6 +83,7 @@ #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9 +#define SAA7164_BOARD_HAUPPAUGE_HVR2200_5 10 #define SAA7164_MAX_UNITS 8 #define SAA7164_TS_NUMBER_OF_LINES 312 diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h index cbfc444..22ea211 100644 --- a/drivers/media/video/sn9c102/sn9c102.h +++ b/drivers/media/video/sn9c102/sn9c102.h @@ -21,7 +21,6 @@ #ifndef _SN9C102_H_ #define _SN9C102_H_ -#include <linux/version.h> #include <linux/usb.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 0e07c49..16cb07c5 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -33,6 +33,7 @@ #include <linux/stat.h> #include <linux/mm.h> #include <linux/vmalloc.h> +#include <linux/version.h> #include <linux/page-flags.h> #include <asm/byteorder.h> #include <asm/page.h> @@ -47,8 +48,7 @@ #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.47pre49" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47) +#define SN9C102_MODULE_VERSION "1:1.48" /*****************************************************************************/ @@ -2158,7 +2158,7 @@ sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) { struct v4l2_capability cap = { .driver = "sn9c102", - .version = SN9C102_MODULE_VERSION_CODE, + .version = LINUX_VERSION_CODE, .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING, }; @@ -3187,16 +3187,8 @@ static long sn9c102_ioctl_v4l2(struct file *filp, case VIDIOC_S_AUDIO: return sn9c102_vidioc_s_audio(cam, arg); - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - case VIDIOC_ENUM_FRAMEINTERVALS: - return -EINVAL; - default: - return -EINVAL; + return -ENOTTY; } } diff --git a/drivers/media/video/tlg2300/Makefile b/drivers/media/video/tlg2300/Makefile index 81bb7fd..ea09b9a 100644 --- a/drivers/media/video/tlg2300/Makefile +++ b/drivers/media/video/tlg2300/Makefile @@ -2,8 +2,8 @@ poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/video/tlg2300/pd-common.h index 46066bd..56564e6 100644 --- a/drivers/media/video/tlg2300/pd-common.h +++ b/drivers/media/video/tlg2300/pd-common.h @@ -1,7 +1,6 @@ #ifndef PD_COMMON_H #define PD_COMMON_H -#include <linux/version.h> #include <linux/fs.h> #include <linux/wait.h> #include <linux/list.h> diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/video/tlg2300/pd-dvb.c index edd78f8..d0da11a 100644 --- a/drivers/media/video/tlg2300/pd-dvb.c +++ b/drivers/media/video/tlg2300/pd-dvb.c @@ -7,7 +7,7 @@ #include "vendorcmds.h" #include <linux/sched.h> -#include <asm/atomic.h> +#include <linux/atomic.h> static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb); diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c index 99c81a9..129f135 100644 --- a/drivers/media/video/tlg2300/pd-main.c +++ b/drivers/media/video/tlg2300/pd-main.c @@ -531,3 +531,4 @@ module_exit(poseidon_exit); MODULE_AUTHOR("Telegent Systems"); MODULE_DESCRIPTION("For tlg2300-based USB device "); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.2"); diff --git a/drivers/media/video/tlg2300/pd-radio.c b/drivers/media/video/tlg2300/pd-radio.c index fae84c2..4fad1df 100644 --- a/drivers/media/video/tlg2300/pd-radio.c +++ b/drivers/media/video/tlg2300/pd-radio.c @@ -6,7 +6,6 @@ #include <linux/usb.h> #include <linux/i2c.h> #include <media/v4l2-dev.h> -#include <linux/version.h> #include <linux/mm.h> #include <linux/mutex.h> #include <media/v4l2-ioctl.h> @@ -149,7 +148,6 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "tele-radio", sizeof(v->driver)); strlcpy(v->card, "Telegent Poseidon", sizeof(v->card)); usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info)); - v->version = KERNEL_VERSION(0, 0, 1); v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index 3387187..aea1e3b 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -2,5 +2,5 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision- obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 8f52661..3103d0d 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -24,6 +24,7 @@ #include <linux/list.h> +#include <linux/module.h> #include <media/v4l2-dev.h> #include <media/tuner.h> #include "usbvision.h" diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index ea8ea8a..5a74f5e 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -45,7 +45,6 @@ * */ -#include <linux/version.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/timer.h> @@ -77,15 +76,7 @@ #define DRIVER_ALIAS "USBVision" #define DRIVER_DESC "USBVision USB Video Device Driver for Linux" #define DRIVER_LICENSE "GPL" -#define USBVISION_DRIVER_VERSION_MAJOR 0 -#define USBVISION_DRIVER_VERSION_MINOR 9 -#define USBVISION_DRIVER_VERSION_PATCHLEVEL 10 -#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\ -USBVISION_DRIVER_VERSION_MINOR,\ -USBVISION_DRIVER_VERSION_PATCHLEVEL) -#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) \ -"." __stringify(USBVISION_DRIVER_VERSION_MINOR) \ -"." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) +#define USBVISION_VERSION_STRING "0.9.11" #define ENABLE_HEXDUMP 0 /* Enable if you need it */ @@ -516,7 +507,6 @@ static int vidioc_querycap(struct file *file, void *priv, usbvision_device_data[usbvision->dev_model].model_string, sizeof(vc->card)); usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info)); - vc->version = USBVISION_DRIVER_VERSION; vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index a4db26f..254d326 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -20,7 +20,7 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include "uvcvideo.h" @@ -1016,7 +1016,8 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, menu_info = &mapping->menu_info[query_menu->index]; - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { + if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && + (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) { s32 bitmap; if (!ctrl->cached) { @@ -1225,7 +1226,8 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, /* Valid menu indices are reported by the GET_RES request for * UVC controls that support it. */ - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { + if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && + (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) { if (!ctrl->cached) { ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) @@ -1664,8 +1666,8 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, return -EINVAL; } - /* Search for the matching (GUID/CS) control in the given device */ - list_for_each_entry(entity, &dev->entities, list) { + /* Search for the matching (GUID/CS) control on the current chain */ + list_for_each_entry(entity, &chain->entities, chain) { unsigned int i; if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT || diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 1f962dc..135e3ca 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -31,6 +31,7 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> +#include <linux/version.h> #include <asm/atomic.h> #include <asm/unaligned.h> @@ -113,6 +114,11 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_RGBP, .fcc = V4L2_PIX_FMT_RGB565, }, + { + .name = "H.264", + .guid = UVC_GUID_FORMAT_H264, + .fcc = V4L2_PIX_FMT_H264, + }, }; /* ------------------------------------------------------------------------ @@ -1591,12 +1597,12 @@ static void uvc_delete(struct uvc_device *dev) { struct list_head *p, *n; - usb_put_intf(dev->intf); - usb_put_dev(dev->udev); - uvc_status_cleanup(dev); uvc_ctrl_cleanup_device(dev); + usb_put_intf(dev->intf); + usb_put_dev(dev->udev); + if (dev->vdev.dev) v4l2_device_unregister(&dev->vdev); #ifdef CONFIG_MEDIA_CONTROLLER @@ -1857,7 +1863,7 @@ static int uvc_probe(struct usb_interface *intf, sizeof(dev->mdev.serial)); strcpy(dev->mdev.bus_info, udev->devpath); dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); - dev->mdev.driver_version = DRIVER_VERSION_NUMBER; + dev->mdev.driver_version = LINUX_VERSION_CODE; if (media_device_register(&dev->mdev) < 0) goto error; @@ -2120,6 +2126,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Dell XPS M1330 (OmniVision OV7670 webcam) */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x05a9, + .idProduct = 0x7670, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_DEF }, /* Apple Built-In iSight */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2130,6 +2145,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_BUILTIN_ISIGHT }, + /* Foxlink ("HP Webcam" on HP Mini 5103) */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x05c8, + .idProduct = 0x0403, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, /* Genesys Logic USB 2.0 PC Camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2321,6 +2345,14 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_DEF }, + /* The Imaging Source USB CCD cameras */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x199e, + .idProduct = 0x8102, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0 }, /* Bodelin ProScopeHR */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_HI diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index f90ce9f..677691c 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -19,7 +19,7 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include "uvcvideo.h" diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 5afdbb7..1030479 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -21,7 +21,7 @@ #include <linux/vmalloc.h> #include <linux/mm.h> #include <linux/wait.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> @@ -32,7 +32,7 @@ * UVC ioctls */ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, - struct uvc_xu_control_mapping *xmap, int old) + struct uvc_xu_control_mapping *xmap) { struct uvc_control_mapping *map; unsigned int size; @@ -58,13 +58,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, break; case V4L2_CTRL_TYPE_MENU: - if (old) { - uvc_trace(UVC_TRACE_CONTROL, "V4L2_CTRL_TYPE_MENU not " - "supported for UVCIOC_CTRL_MAP_OLD.\n"); - ret = -EINVAL; - goto done; - } - /* Prevent excessive memory consumption, as well as integer * overflows. */ @@ -92,7 +85,7 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, default: uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type " "%u.\n", xmap->v4l2_type); - ret = -EINVAL; + ret = -ENOTTY; goto done; } @@ -547,20 +540,6 @@ static int uvc_v4l2_release(struct file *file) return 0; } -static void uvc_v4l2_ioctl_warn(void) -{ - static int warned; - - if (warned) - return; - - uvc_printk(KERN_INFO, "Deprecated UVCIOC_CTRL_{ADD,MAP_OLD,GET,SET} " - "ioctls will be removed in 2.6.42.\n"); - uvc_printk(KERN_INFO, "See http://www.ideasonboard.org/uvc/upgrade/ " - "for upgrade instructions.\n"); - warned = 1; -} - static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); @@ -580,7 +559,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) strlcpy(cap->card, vdev->name, sizeof cap->card); usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = DRIVER_VERSION_NUMBER; + cap->version = LINUX_VERSION_CODE; if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; @@ -1041,37 +1020,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd); return -EINVAL; - /* Dynamic controls. UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD, - * UVCIOC_CTRL_GET and UVCIOC_CTRL_SET are deprecated and scheduled for - * removal in 2.6.42. - */ - case __UVCIOC_CTRL_ADD: - uvc_v4l2_ioctl_warn(); - return -EEXIST; - - case __UVCIOC_CTRL_MAP_OLD: - uvc_v4l2_ioctl_warn(); - case __UVCIOC_CTRL_MAP: case UVCIOC_CTRL_MAP: - return uvc_ioctl_ctrl_map(chain, arg, - cmd == __UVCIOC_CTRL_MAP_OLD); - - case __UVCIOC_CTRL_GET: - case __UVCIOC_CTRL_SET: - { - struct uvc_xu_control *xctrl = arg; - struct uvc_xu_control_query xqry = { - .unit = xctrl->unit, - .selector = xctrl->selector, - .query = cmd == __UVCIOC_CTRL_GET - ? UVC_GET_CUR : UVC_SET_CUR, - .size = xctrl->size, - .data = xctrl->data, - }; - - uvc_v4l2_ioctl_warn(); - return uvc_xu_ctrl_query(chain, &xqry); - } + return uvc_ioctl_ctrl_map(chain, arg); case UVCIOC_CTRL_QUERY: return uvc_xu_ctrl_query(chain, arg); diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 6f147de..af5c040 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -19,7 +19,7 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <asm/unaligned.h> #include <media/v4l2-common.h> @@ -790,8 +790,12 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) for (i = 0; i < UVC_URBS; ++i) { if (stream->urb_buffer[i]) { +#ifndef CONFIG_DMA_NONCOHERENT usb_free_coherent(stream->dev->udev, stream->urb_size, stream->urb_buffer[i], stream->urb_dma[i]); +#else + kfree(stream->urb_buffer[i]); +#endif stream->urb_buffer[i] = NULL; } } @@ -831,9 +835,14 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, for (; npackets > 1; npackets /= 2) { for (i = 0; i < UVC_URBS; ++i) { stream->urb_size = psize * npackets; +#ifndef CONFIG_DMA_NONCOHERENT stream->urb_buffer[i] = usb_alloc_coherent( stream->dev->udev, stream->urb_size, gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]); +#else + stream->urb_buffer[i] = + kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN); +#endif if (!stream->urb_buffer[i]) { uvc_free_urb_buffers(stream); break; @@ -908,10 +917,14 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->context = stream; urb->pipe = usb_rcvisocpipe(stream->dev->udev, ep->desc.bEndpointAddress); +#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->transfer_dma = stream->urb_dma[i]; +#else + urb->transfer_flags = URB_ISO_ASAP; +#endif urb->interval = ep->desc.bInterval; urb->transfer_buffer = stream->urb_buffer[i]; - urb->transfer_dma = stream->urb_dma[i]; urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; @@ -969,8 +982,10 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, usb_fill_bulk_urb(urb, stream->dev->udev, pipe, stream->urb_buffer[i], size, uvc_video_complete, stream); +#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = stream->urb_dma[i]; +#endif stream->urb[i] = urb; } @@ -1252,7 +1267,25 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) if (!enable) { uvc_uninit_video(stream, 1); - usb_set_interface(stream->dev->udev, stream->intfnum, 0); + if (stream->intf->num_altsetting > 1) { + usb_set_interface(stream->dev->udev, + stream->intfnum, 0); + } else { + /* UVC doesn't specify how to inform a bulk-based device + * when the video stream is stopped. Windows sends a + * CLEAR_FEATURE(HALT) request to the video streaming + * bulk endpoint, mimic the same behaviour. + */ + unsigned int epnum = stream->header.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK; + unsigned int dir = stream->header.bEndpointAddress + & USB_ENDPOINT_DIR_MASK; + unsigned int pipe; + + pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir; + usb_clear_halt(stream->dev->udev, pipe); + } + uvc_queue_enable(&stream->queue, 0); return 0; } diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index cf2401a..bc446ba 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -1,106 +1,16 @@ #ifndef _USB_VIDEO_H_ #define _USB_VIDEO_H_ -#include <linux/kernel.h> -#include <linux/videodev2.h> - -#ifndef __KERNEL__ -/* - * This header provides binary compatibility with applications using the private - * uvcvideo API. This API is deprecated and will be removed in 2.6.42. - * Applications should be recompiled against the public linux/uvcvideo.h header. - */ -#warn "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead." - -/* - * Dynamic controls - */ - -/* Data types for UVC control data */ -#define UVC_CTRL_DATA_TYPE_RAW 0 -#define UVC_CTRL_DATA_TYPE_SIGNED 1 -#define UVC_CTRL_DATA_TYPE_UNSIGNED 2 -#define UVC_CTRL_DATA_TYPE_BOOLEAN 3 -#define UVC_CTRL_DATA_TYPE_ENUM 4 -#define UVC_CTRL_DATA_TYPE_BITMASK 5 - -/* Control flags */ -#define UVC_CONTROL_SET_CUR (1 << 0) -#define UVC_CONTROL_GET_CUR (1 << 1) -#define UVC_CONTROL_GET_MIN (1 << 2) -#define UVC_CONTROL_GET_MAX (1 << 3) -#define UVC_CONTROL_GET_RES (1 << 4) -#define UVC_CONTROL_GET_DEF (1 << 5) -#define UVC_CONTROL_RESTORE (1 << 6) -#define UVC_CONTROL_AUTO_UPDATE (1 << 7) - -#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ - UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ - UVC_CONTROL_GET_DEF) - -struct uvc_menu_info { - __u32 value; - __u8 name[32]; -}; - -struct uvc_xu_control_mapping { - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; - - __u8 size; - __u8 offset; - __u32 v4l2_type; - __u32 data_type; - - struct uvc_menu_info __user *menu_info; - __u32 menu_count; - - __u32 reserved[4]; -}; - -#endif - -struct uvc_xu_control_info { - __u8 entity[16]; - __u8 index; - __u8 selector; - __u16 size; - __u32 flags; -}; - -struct uvc_xu_control_mapping_old { - __u8 reserved[64]; -}; - -struct uvc_xu_control { - __u8 unit; - __u8 selector; - __u16 size; - __u8 __user *data; -}; - #ifndef __KERNEL__ -#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) -#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) -#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) -#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) -#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) -#else -#define __UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) -#define __UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) -#define __UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) -#define __UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) -#define __UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) -#endif - -#ifdef __KERNEL__ +#error "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead." +#endif /* __KERNEL__ */ +#include <linux/kernel.h> #include <linux/poll.h> #include <linux/usb.h> #include <linux/usb/video.h> #include <linux/uvcvideo.h> +#include <linux/videodev2.h> #include <media/media-device.h> #include <media/v4l2-device.h> @@ -179,12 +89,15 @@ struct uvc_xu_control { { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_H264 \ + { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} + /* ------------------------------------------------------------------------ * Driver specific constants. */ -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 1, 0) -#define DRIVER_VERSION "v1.1.0" +#define DRIVER_VERSION "1.1.1" /* Number of isochronous URBs. */ #define UVC_URBS 5 @@ -700,6 +613,4 @@ extern struct usb_host_endpoint *uvc_find_endpoint( void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, struct uvc_buffer *buf); -#endif /* __KERNEL__ */ - #endif diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h index f3f6400..d7166af 100644 --- a/drivers/media/video/zoran/zoran.h +++ b/drivers/media/video/zoran/zoran.h @@ -41,10 +41,6 @@ struct zoran_sync { }; -#define MAJOR_VERSION 0 /* driver major version */ -#define MINOR_VERSION 10 /* driver minor version */ -#define RELEASE_VERSION 0 /* release version */ - #define ZORAN_NAME "ZORAN" /* name of the device */ #define ZR_DEVNAME(zr) ((zr)->name) diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 79b04ac..c3602d6 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -123,9 +123,12 @@ int zr36067_debug = 1; module_param_named(debug, zr36067_debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-5)"); +#define ZORAN_VERSION "0.10.1" + MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); MODULE_AUTHOR("Serguei Miridonov"); MODULE_LICENSE("GPL"); +MODULE_VERSION(ZORAN_VERSION); #define ZR_DEVICE(subven, subdev, data) { \ .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ @@ -1459,8 +1462,8 @@ static int __init zoran_init(void) { int res; - printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n", - MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION); + printk(KERN_INFO "Zoran MJPEG board driver version %s\n", + ZORAN_VERSION); /* check the parameters we have been given, adjust if necessary */ if (v4l_nbufs < 2) diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index 2771d81..d4d05d2 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -44,7 +44,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/version.h> #include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> @@ -1538,8 +1537,6 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability strncpy(cap->driver, "zoran", sizeof(cap->driver)-1); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(zr->pci_dev)); - cap->version = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION, - RELEASE_VERSION); cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY; return 0; |